[sympycore commit] r841 - in trunk: . doc/html src sympycore sympycore/arithmetic sympycore/basealgebra sympycore/ca...

0 views
Skip to first unread message

codesite...@google.com

unread,
Mar 2, 2008, 5:43:14 PM3/2/08
to sympycor...@googlegroups.com
Author: pearu.peterson
Date: Sun Mar 2 14:42:47 2008
New Revision: 841

Added:
trunk/src/pair_ext.c
trunk/sympycore/pair.py
Removed:
trunk/src/apair_ext.c
trunk/sympycore/apair.py
Modified:
trunk/doc/html/userguide.html
trunk/setup.py
trunk/src/mk_pairs_iops.py
trunk/src/mk_pairs_ops.py
trunk/sympycore/arithmetic/infinity.py
trunk/sympycore/basealgebra/pairs.py
trunk/sympycore/basealgebra/pairs_expand.py
trunk/sympycore/basealgebra/pairs_iops.py
trunk/sympycore/basealgebra/pairs_ops.py
trunk/sympycore/calculus/integration.py
trunk/sympycore/core.py

Log:
Renamed APair to Pair, it has read-only head and data attributes for
backward compatibility. Impl Pair repr method.

Modified: trunk/doc/html/userguide.html
==============================================================================
--- trunk/doc/html/userguide.html (original)
+++ trunk/doc/html/userguide.html Sun Mar 2 14:42:47 2008
@@ -436,7 +436,7 @@
>>> Calculus('a-3/4+b**2')
Calculus('a + b**2 - 3/4')
>>> Calculus('a-3/4+b**2').func
-<bound method BasicType.Add of <class 'sympycore.calculus.algebra.Calculus'>>
+<bound method type.Add of <class 'sympycore.calculus.algebra.Calculus'>>
>>> Calculus('a-3/4+b**2').args
[Calculus('a'), Calculus('-3/4'), Calculus('b**2')]
</pre>

Modified: trunk/setup.py
==============================================================================
--- trunk/setup.py (original)
+++ trunk/setup.py Sun Mar 2 14:42:47 2008
@@ -15,9 +15,9 @@
import os
if os.path.exists('MANIFEST'): os.remove('MANIFEST')
from distutils.core import Extension
-apair_ext = Extension('sympycore.apair_ext',
- sources = [os.path.join('src','apair_ext.c')],
- )
+pair_ext = Extension('sympycore.pair_ext',
+ sources = [os.path.join('src','pair_ext.c')],
+ )

if __name__ == '__main__':
from distutils.core import setup
@@ -49,7 +49,7 @@
'sympycore.polynomials',
'sympycore.physics',
],
- ext_modules = [apair_ext],
+ ext_modules = [pair_ext],
package_dir = {'sympycore': 'sympycore'},
)


Modified: trunk/src/mk_pairs_iops.py
==============================================================================
--- trunk/src/mk_pairs_iops.py (original)
+++ trunk/src/mk_pairs_iops.py Sun Mar 2 14:42:47 2008
@@ -19,10 +19,10 @@
DO NOT CHANGE THIS FILE DIRECTLY!!!
"""

-from ..core import APair
+from ..core import Pair
from ..arithmetic.numbers import Complex, Float, FractionTuple, try_power
from ..utils import NUMBER, TERMS, FACTORS
-new = APair.__new__
+new = Pair.__new__
'''

def main():

Modified: trunk/src/mk_pairs_ops.py
==============================================================================
--- trunk/src/mk_pairs_ops.py (original)
+++ trunk/src/mk_pairs_ops.py Sun Mar 2 14:42:47 2008
@@ -18,13 +18,13 @@
DO NOT CHANGE THIS FILE DIRECTLY!!!
"""

-from ..core import APair
+from ..core import Pair
from ..utils import NUMBER, SYMBOL, TERMS, FACTORS
from ..arithmetic.numbers import (normalized_fraction,
FractionTuple, try_power, numbertypes)
from ..arithmetic.infinity import Infinity

-new = APair.__new__
+new = Pair.__new__

def div(a, b, cls):
tb = type(b)

Added: trunk/src/pair_ext.c
==============================================================================
--- (empty file)
+++ trunk/src/pair_ext.c Sun Mar 2 14:42:47 2008
@@ -0,0 +1,320 @@
+#include <Python.h>
+//#include "structmember.h"
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *head;
+ PyObject *data;
+ long hash;
+} Pair;
+
+static PyTypeObject PairType;
+
+#define Pair_Check(op) PyObject_TypeCheck(op, &PairType)
+#define Pair_CheckExact(op) ((op)->ob_type == &PairType)
+
+static int
+Pair_traverse(Pair *self, visitproc visit, void *arg)
+{
+ int vret;
+
+ if (self->head) {
+ vret = visit(self->head, arg);
+ if (vret != 0)
+ return vret;
+ }
+ if (self->data) {
+ vret = visit(self->data, arg);
+ if (vret != 0)
+ return vret;
+ }
+
+ return 0;
+}
+
+static int
+Pair_clear(Pair *self)
+{
+ PyObject *tmp;
+
+ tmp = self->head;
+ self->head = NULL;
+ Py_XDECREF(tmp);
+
+ tmp = self->data;
+ self->data = NULL;
+ Py_XDECREF(tmp);
+
+ return 0;
+}
+
+static void
+Pair_dealloc(Pair* self)
+{
+ Pair_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+Pair_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ Py_ssize_t len;
+ Pair *self;
+
+ self = (Pair *)type->tp_alloc(type, 0);
+
+ if (self != NULL) {
+
+ if (!PyTuple_Check(args)) {
+ PyErr_SetString(PyExc_SystemError,
+ "new style getargs format but argument is not a tuple");
+ return NULL;
+ }
+
+ len = PyTuple_GET_SIZE(args);
+ if (len!=2) {
+ PyErr_SetString(PyExc_TypeError,
+ "Pair.__new__ expects exactly 2 arguments: (head, data)");
+ return NULL;
+ }
+
+ self->head = PyTuple_GET_ITEM(args, 0);
+ if (self->head==NULL) {
+ Py_DECREF(self);
+ return NULL;
+ }
+
+ self->data = PyTuple_GET_ITEM(args, 1);
+ if (self->data==NULL) {
+ Py_DECREF(self);
+ return NULL;
+ }
+
+ Py_INCREF(self->head);
+ Py_INCREF(self->data);
+
+ self->hash = -1;
+ }
+
+ return (PyObject *)self;
+}
+
+static PyObject *
+Pair_item(register Pair *self, register Py_ssize_t i)
+{
+ if (i==0) {
+ Py_INCREF(self->head);
+ return self->head;
+ }
+ if (i==1) {
+ Py_INCREF(self->data);
+ return self->data;
+ }
+ PyErr_SetString(PyExc_IndexError, "Pair index out of range [0,1]");
+ return NULL;
+}
+
+PyObject *
+Pair_slice(PyObject *op, Py_ssize_t i, Py_ssize_t j)
+{
+ Py_ssize_t len;
+ register PyTupleObject *np;
+ register Pair *self = (Pair*)op;
+ if (op == NULL || !Pair_Check(op)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ if (i<0) i=0;
+ if (j>2) j=2;
+ if (j<i) j=i;
+ len = j-i;
+ np = (PyTupleObject *)PyTuple_New(len);
+ if (len==2) {
+ PyObject *v = self->head;
+ Py_INCREF(v);
+ np->ob_item[0] = v;
+ v = self->data;
+ Py_INCREF(v);
+ np->ob_item[1] = v;
+ } else if ((len==1) && (i==0)) {
+ PyObject *v = self->head;
+ Py_INCREF(v);
+ np->ob_item[0] = v;
+ } else if ((len==1) && (i==1)) {
+ PyObject *v = self->data;
+ Py_INCREF(v);
+ np->ob_item[0] = v;
+ }
+ return (PyObject *)np;
+}
+
+static long dict_hash(PyObject *d);
+
+static long
+tuple2_hash(PyObject *item0, PyObject *item1) {
+ register long hash, h;
+ long mult = 1000003L;
+ hash = 0x345678L;
+ h = PyObject_Hash(item0);
+ hash = (hash ^ h) * mult;
+ mult += 82524L;
+ if (PyDict_Check(item1)) {
+ h = dict_hash(item1);
+ } else
+ h = PyObject_Hash(item1);
+ hash = (hash ^ h) * mult;
+ mult += 82524L;
+ hash += 97531L;
+ if (hash==-1)
+ hash = -2;
+ return hash;
+}
+
+/*
+ hash(dict) == hash(frozenset(dict.items()))
+ */
+static long
+dict_hash(PyObject *d) {
+ Py_ssize_t i;
+ PyObject *key, *value;
+ long h, hash = 1927868237L;
+ hash *= PyDict_Size(d) + 1;
+ i = 0;
+ while (PyDict_Next(d, &i, &key, &value)) {
+ h = tuple2_hash(key, value);
+ hash ^= (h ^ (h << 16) ^ 89869747L) * 3644798167u;
+ }
+ hash = hash * 69069L + 907133923L;
+ if (hash == -1)
+ hash = 590923713L;
+ return hash;
+}
+
+/*
+ if isinstance(y, dict):
+ hash(Pair(x,y)) == hash((x,frozenset(y.items()))
+ else:
+ hash(Pair(x,y)) == hash((x,y))
+ */
+static long
+Pair_hash(PyObject *self)
+{
+ Pair *o = (Pair *)self;
+ if (o->hash!=-1)
+ return o->hash;
+ o->hash = tuple2_hash(o->head, o->data);
+ return o->hash;
+}
+
+static PyObject *
+Pair_gethead(Pair *self, void *closure)
+{
+ Py_INCREF(self->head);
+ return self->head;
+}
+
+static PyObject *
+Pair_getdata(Pair *self, void *closure)
+{
+ Py_INCREF(self->data);
+ return self->data;
+}
+
+static PyObject *
+Pair_repr(Pair *v)
+{
+ return PyString_Format(PyString_FromString("%s(%r, %r)"),
+ PyTuple_Pack(3,
+ PyString_FromString(v->ob_type->tp_name),
+ v->head,
+ v->data));
+}
+
+static PyGetSetDef Pair_getseters[] = {
+ {"head", (getter)Pair_gethead, NULL, "head", NULL},
+ {"data", (getter)Pair_getdata, NULL, "data", NULL},
+ {NULL} /* Sentinel */
+};
+
+/*
+ Pair_item provides a fast way to access head and data data member.
+ Pair_slice is used in a idiom `head, data = <Pair instance>[:]`.
+ */
+
+static PySequenceMethods Pair_as_sequence = {
+ 0, /* sq_length */
+ 0, /* sq_concat */
+ 0, /* sq_repeat */
+ (ssizeargfunc)Pair_item, /* sq_item */
+ (ssizessizeargfunc)Pair_slice, /* sq_slice */
+ 0, /* sq_ass_item */
+ 0, /* sq_ass_slice */
+ 0, /* sq_contains */
+};
+
+static PyTypeObject PairType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "pair_ext.Pair", /*tp_name*/
+ sizeof(Pair), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Pair_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ (reprfunc)Pair_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ &Pair_as_sequence, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ Pair_hash, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
+ "Holds a pair (head, data).", /* tp_doc */
+ (traverseproc)Pair_traverse, /* tp_traverse */
+ (inquiry)Pair_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ Pair_getseters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ Pair_new, /* tp_new */
+};
+
+static PyMethodDef module_methods[] = {
+ {NULL} /* Sentinel */
+};
+
+#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
+#define PyMODINIT_FUNC void
+#endif
+PyMODINIT_FUNC
+initpair_ext(void)
+{
+ PyObject* m;
+
+ if (PyType_Ready(&PairType) < 0)
+ return;
+
+ m = Py_InitModule3("pair_ext", module_methods,
+ "Provides extension type Pair.");
+
+ if (m == NULL)
+ return;
+
+ Py_INCREF(&PairType);
+ PyModule_AddObject(m, "Pair", (PyObject *)&PairType);
+}

Modified: trunk/sympycore/arithmetic/infinity.py
==============================================================================
--- trunk/sympycore/arithmetic/infinity.py (original)
+++ trunk/sympycore/arithmetic/infinity.py Sun Mar 2 14:42:47 2008
@@ -129,7 +129,7 @@
if a is not None:
lhs, rhs = a
return '%s + (%s)' % (lhs, rhs)
- return 'oo*(%s)' % (d)
+ return 'oo*(%s)' % (d,)

def __eq__(self, other):
if isinstance(other, type(self)):

Modified: trunk/sympycore/basealgebra/pairs.py
==============================================================================
--- trunk/sympycore/basealgebra/pairs.py (original)
+++ trunk/sympycore/basealgebra/pairs.py Sun Mar 2 14:42:47 2008
@@ -8,7 +8,7 @@

__all__ = ['CommutativeRingWithPairs']

-from ..core import APair
+from ..core import Pair
from ..core import classes
from ..utils import str_SUM, str_PRODUCT, str_POWER, str_APPLY,
str_SYMBOL, str_NUMBER
from ..utils import TERMS, FACTORS, SYMBOL, NUMBER, APPLY, POW, TUPLE, head_to_string
@@ -27,20 +27,17 @@

from .pairs_expand import expand

-class CommutativeRingWithPairs(APair, CommutativeRing):
+class CommutativeRingWithPairs(Pair, CommutativeRing):
""" Implementation of a commutative ring where sums and products
are represented as dictionaries of pairs.
"""
- __slots__ = ['_symbols', '_symbols_data', '_has_active',
- #'head', 'data','_hash',
- ]
+ #__slots__ = ['_symbols', '_symbols_data']

one_c = 1 # one element of coefficient algebra
one_e = 1 # one element of exponent algebra
zero_c = 0 # zero element of coefficient algebra
zero_e = 0 # zero element of exponent algebra

- _hash = None
_symbols = None
_symbols_data = None

@@ -60,7 +57,7 @@

__repr__ = CommutativeRing.__repr__

- def __new__(cls, data, head=None, new=APair.__new__):
+ def __new__(cls, data, head=None, new=Pair.__new__):
if head is None:
if type(data) is cls:
return data
@@ -79,21 +76,10 @@
return self.data == other
return False

- def __hash2__(self):
- h = self._hash
- if not h:
- data = self.data
- if type(data) is dict:
- h = hash(frozenset(data.iteritems()))
- else:
- h = hash(data)
- self._hash = h
- return h
-
def __nonzero__(self):
return self.head is not NUMBER or bool(self.data)

- def copy(self, new=APair.__new__):
+ def copy(self, new=Pair.__new__):
""" Return a copy of self.
"""
head = self.head
@@ -421,13 +407,13 @@
return r

@classmethod
- def Symbol(cls, obj, new=APair.__new__):
+ def Symbol(cls, obj, new=Pair.__new__):
""" Construct new symbol instance as an algebra element.
"""
return new(cls, SYMBOL, obj)

@classmethod
- def Number(cls, obj, new=APair.__new__):
+ def Number(cls, obj, new=Pair.__new__):
""" Construct new number instance as an algebra number.
"""
return new(cls, NUMBER, obj)

Modified: trunk/sympycore/basealgebra/pairs_expand.py
==============================================================================
--- trunk/sympycore/basealgebra/pairs_expand.py (original)
+++ trunk/sympycore/basealgebra/pairs_expand.py Sun Mar 2 14:42:47 2008
@@ -5,14 +5,14 @@

__docformat__ = "restructuredtext"

-from ..core import APair
+from ..core import Pair
from ..arithmetic.numbers import Complex, Float, FractionTuple, try_power
from ..arithmetic.number_theory import multinomial_coefficients
from ..utils import NUMBER, TERMS, FACTORS
from .pairs_iops import inplace_add2, return_terms, return_factors
from .pairs_ops import expand_mul_method

-new = APair.__new__
+new = Pair.__new__

def expand(self):
""" Return self as expanded expression.

Modified: trunk/sympycore/basealgebra/pairs_iops.py
==============================================================================
--- trunk/sympycore/basealgebra/pairs_iops.py (original)
+++ trunk/sympycore/basealgebra/pairs_iops.py Sun Mar 2 14:42:47 2008
@@ -7,10 +7,10 @@
DO NOT CHANGE THIS FILE DIRECTLY!!!
"""

-from ..core import APair
+from ..core import Pair
from ..arithmetic.numbers import Complex, Float, FractionTuple, try_power
from ..utils import NUMBER, TERMS, FACTORS
-new = APair.__new__
+new = Pair.__new__


Modified: trunk/sympycore/basealgebra/pairs_ops.py
==============================================================================
--- trunk/sympycore/basealgebra/pairs_ops.py (original)
+++ trunk/sympycore/basealgebra/pairs_ops.py Sun Mar 2 14:42:47 2008
@@ -6,13 +6,13 @@
DO NOT CHANGE THIS FILE DIRECTLY!!!
"""

-from ..core import APair
+from ..core import Pair
from ..utils import NUMBER, SYMBOL, TERMS, FACTORS
from ..arithmetic.numbers import (normalized_fraction,
FractionTuple, try_power, numbertypes)
from ..arithmetic.infinity import Infinity

-new = APair.__new__
+new = Pair.__new__

def div(a, b, cls):
tb = type(b)

Modified: trunk/sympycore/calculus/integration.py
==============================================================================
--- trunk/sympycore/calculus/integration.py (original)
+++ trunk/sympycore/calculus/integration.py Sun Mar 2 14:42:47 2008
@@ -10,7 +10,7 @@
Symbol = Calculus.Symbol

def unknown(expr):
- raise NotImplementedError("don't know how to integrate %s" % expr)
+ raise NotImplementedError("don't know how to integrate %s" % (expr,))

def integrate_indefinite(expr, x):
head = expr.head

Modified: trunk/sympycore/core.py
==============================================================================
--- trunk/sympycore/core.py (original)
+++ trunk/sympycore/core.py Sun Mar 2 14:42:47 2008
@@ -2,12 +2,15 @@
"""

__docformat__ = 'restructuredtext'
-__all__ = ['classes', 'APair']
+__all__ = ['classes', 'Pair']

try:
- from .apair_ext import APair
-except ImportError:
- from .apair import APair
+ from .pair_ext import Pair
+except ImportError, msg:
+ msg = str(msg)
+ if msg!='No module named pair_ext':
+ print msg
+ from .pair import Pair

class Holder:
""" Holds pairs ``(name, value)`` as instance attributes.

Added: trunk/sympycore/pair.py
==============================================================================
--- (empty file)
+++ trunk/sympycore/pair.py Sun Mar 2 14:42:47 2008
@@ -0,0 +1,97 @@
+# -*- coding: latin-1 -*-
+"""This module implements a pure python Pair class.
+
+In python code, usage of the following idioms are recommended:
+
+ head, data = <Pair instance>[:]
+
+Some benchmarks.
+
+1) Pair is a pure Python new-style class:
+
+>>> %timeit Pair(1,2)
+1000000 loops, best of 3: 818 ns per loop
+
+>>> a=Pair(1,2)
+>>> %timeit head, data = a.head, a.data
+1000000 loops, best of 3: 213 ns per loop
+>>> %timeit head, data = a[:]
+1000000 loops, best of 3: 704 ns per loop
+>>> %timeit head, data = a
+100000 loops, best of 3: 2.3 �s per loop
+>>> %timeit head, data = a[0], a[1]
+1000000 loops, best of 3: 1.03 �s per loop
+
+2) Pair is object type implemented in extension module:
+
+>>> %timeit Pair(1,2)
+1000000 loops, best of 3: 191 ns per loop
+
+>>> a=Pair(1,2)
+>>> %timeit head, data = a.head, a.data
+1000000 loops, best of 3: 187 ns per loop
+>>> %timeit head, data = a[:]
+10000000 loops, best of 3: 132 ns per loop
+>>> %timeit head, data = a
+1000000 loops, best of 3: 716 ns per loop
+>>> %timeit head, data = a[0], a[1]
+10000000 loops, best of 3: 173 ns per loop
+
+3) Pair is derived from tuple (cannot use this approach as it breaks
+numpy array support):
+
+>>> a=Pair(1,2)
+>>> %timeit Pair(1,2)
+1000000 loops, best of 3: 1.18 �s per loop
+
+>>> a=Pair(1,2)
+>>> %timeit head, data = a.head, a.data
+1000000 loops, best of 3: 346 ns per loop
+>>> %timeit head, data = a[0], a[1]
+10000000 loops, best of 3: 174 ns per loop
+>>> %timeit head, data = a[:]
+10000000 loops, best of 3: 135 ns per loop
+>>> %timeit head, data = a
+10000000 loops, best of 3: 159 ns per loop
+
+
+
+"""
+
+
+class Pair(object):
+ """ Holds a pair of Python objects.
+
+ This is pure Python version.
+ """
+
+ __slots__ = ['head', 'data', '_hash']
+ _hash = None
+
+ def __new__(cls, head, data, new = object.__new__):
+ obj = new(cls)
+ obj.head = head
+ obj.data = data
+ return obj
+
+ def __repr__(self):
+ return '%s(%r, %r)' % (type(self).__name__, self.head, self.data)
+
+ def __getslice__(self, start, end):
+ return (self.head, self.data)[start:end]
+
+ def __getitem__(self, index):
+ if index is 0: return self.head
+ if index is 1: return self.data
+ raise IndexError
+
+ def __hash__(self):
+ h = self._hash
+ if not h:
+ data = self.data
+ if type(data) is dict:
+ h = hash(frozenset(data.iteritems()))
+ else:
+ h = hash(data)
+ self._hash = h
+ return h

Reply all
Reply to author
Forward
0 new messages