diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..9561fb1 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include README.rst diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..ba85590 --- /dev/null +++ b/README.rst @@ -0,0 +1,24 @@ +Basic Sage Optional Package +=========================== + +This is a basic `Sage `_ optional package containing +nice modules to share to others. + +Installation:: + + sage -pip install sage_sample + +Usage:: + + sage: from sage_sample import * + +Links: Github__, `Python Package Index`__ + +__ https://github.com/nthiery/sage_sample +__ http://pypi.python.org/pypi/sage_sample + +Version 0.1a0 +------------- + +First version. + diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..9207593 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1a0 diff --git a/makefile b/makefile new file mode 100644 index 0000000..457a10b --- /dev/null +++ b/makefile @@ -0,0 +1,35 @@ +all: install test + +install: + sage -pip install --upgrade --no-index -v . + +develop: + sage -pip install --upgrade --no-index -e . + +test: + sage -tp --force-lib sage_sample/*.py sage_sample/*.pyx + +coverage: + sage -coverage sage_sample/* + +doc: + cd docs && sage -sh -c "make html" + +doc-pdf: + cd docs && sage -sh -c "make latexpdf" + +dist: + sage -python setup.py sdist + +register: dist + VERSION=`cat VERSION`; sage -sh -c "twine register dist/sage_sample-$$VERSION.tar.gz" + +upload: dist + VERSION=`cat VERSION`; sage -sh -c "twine upload dist/sage_sample-$$VERSION.tar.gz" + +clean: clean-doc + +clean-doc: + cd docs && sage -sh -c "make clean" + +.PHONY: all install develop test coverage clean clean-doc doc doc-pdf dist register upload diff --git a/sage_sample/__init__.py b/sage_sample/__init__.py new file mode 100644 index 0000000..3fb08e2 --- /dev/null +++ b/sage_sample/__init__.py @@ -0,0 +1,6 @@ +# For sphinx to work, we first need to import the sage library +from sage.all_cmdline import * + +# import stuff of the package +from diophantine_approximation import diophantine_approx +from dirichlet import dirichlet diff --git a/sage_sample/diophantine_approximation.py b/sage_sample/diophantine_approximation.py new file mode 100644 index 0000000..4822542 --- /dev/null +++ b/sage_sample/diophantine_approximation.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +r""" +Diophantine approximation + +EXAMPLES:: + + sage: from sage_sample import diophantine_approx + sage: diophantine_approx(pi, 10) + (22, 7) + +AUTHORS: + +- Sébastien Labbé, November 23, 2016, Sage Days 79, Jerusalem +""" +#***************************************************************************** +# Copyright (C) 2016 Sebastien Labbe +# +# 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/ +#***************************************************************************** + +# Use `import_statements` command to know how to import each sage commands:: +# +# sage: import_statements('round') +# from sage.misc.functional import round + +from sage.functions.other import frac +from sage.misc.functional import round + +def diophantine_approx(alpha, Q): + r""" + Return a diophantine approximation p/q to real number alpha following + Dirichlet Theorem (1842). + + .. NOTES:: + + This function is very slow compared to using continued fractions. + It tests all of the possible values of q. + + INPUT: + + - `alpha` -- real number + - `Q` -- real number > 1 + + OUTPUT: + + - a tuple of integers (p,q) such that `|\alpha q-p|<1/Q`. + + EXAMPLES:: + + sage: from sage_sample import diophantine_approx + sage: diophantine_approx(pi, 10) + (22, 7) + sage: diophantine_approx(pi, 100) + (22, 7) + sage: diophantine_approx(pi, 200) + (355, 113) + sage: diophantine_approx(pi, 1000) + (355, 113) + sage: diophantine_approx(pi, 35000) # not tested, code is very slow + """ + for q in range(1, Q): + if frac(alpha*q) <= 1./Q or 1-1./Q <= frac(alpha*q): + p = round(alpha*q) + return (p,q) + + diff --git a/sage_sample/dirichlet.pyx b/sage_sample/dirichlet.pyx new file mode 100644 index 0000000..dfc57d6 --- /dev/null +++ b/sage_sample/dirichlet.pyx @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +r""" +Dirichlet Diophantine approximation + +EXAMPLES:: + + sage: from sage_sample import dirichlet + sage: dirichlet(pi, 10) + 7 + +AUTHORS: + +- Sébastien Labbé, November 23, 2016, Sage Days 79, Jerusalem +""" +#***************************************************************************** +# Copyright (C) 2016 Sebastien Labbe +# +# 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 libc.math cimport floor + +include "cysignals/signals.pxi" # ctrl-c interrupt block support +include "cysignals/memory.pxi" + +def dirichlet(alpha, Q): + r""" + Return a diophantine approximation p/q to real number alpha following + Dirichlet Theorem (1842). + + .. NOTES:: + + This function is slow compared to using continued fractions. + It tests all of the possible values of q. + + INPUT: + + - `alpha` -- real number + - `Q` -- real number > 1 + + OUTPUT: + + - a tuple of integers (p,q) such that `|\alpha q-p|<1/Q`. + + EXAMPLES:: + + sage: from sage_sample import dirichlet + sage: dirichlet(pi, 10) + 7 + sage: dirichlet(pi, 100) + 7 + sage: dirichlet(pi, 200) + 113 + sage: dirichlet(pi, 1000) + 113 + sage: dirichlet(pi, 35000) # long (1.38s) + 33102 + """ + if not Q > 1: + raise ValueError("argument Q(={}) must be > 1".format(Q)) + cdef double Qinv = 1. / Q + cdef double one_minus_Qinv = 1 - Qinv + cdef double a + cdef long q + for q in range(1, Q): + sig_check() # Check for Keyboard interupt + a = q*alpha + a = a - floor(a) + if a <= Qinv or one_minus_Qinv <= a: + return q + + diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..d33ae38 --- /dev/null +++ b/setup.py @@ -0,0 +1,49 @@ +from setuptools import setup +from codecs import open # To use a consistent encoding +from os import path + +# The next block is if there are some cython files +from setuptools import Extension +from Cython.Build import cythonize +import Cython.Compiler.Options +from sage.env import sage_include_directories + +# Get the long description from the README file +here = path.abspath(path.dirname(__file__)) +with open(path.join(here, 'README.rst'), encoding='utf-8') as f: + long_description = f.read() +with open(path.join(here, 'VERSION'), encoding='utf-8') as f: + version = f.read().strip() + +# Cython modules +ext_modules = [ + Extension('sage_sample.dirichlet', + sources = [path.join('sage_sample','dirichlet.pyx')], + include_dirs=sage_include_directories()) + ] + +setup(name='sage_sample', + version=version, + description="Basic Sage Optional Package", + long_description=long_description, + classifiers=[ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 3 - Alpha', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)', + 'Programming Language :: Python :: 2.7', + 'Topic :: Scientific/Engineering :: Mathematics', + ], + keywords='sagemath', + #keywords='sagemath combinatorics geometry symbolic dynamics', + author='Sebastien Labbe', + author_email='slabbe@ulg.ac.be', + url='https://github.com/nthiery/sage_sample', + license = "GPL", + packages=['sage_sample'], + ext_modules=cythonize(ext_modules), +) +