[SciPy-dev] Generic polynomials class (was Re: Volunteer for Scipy Project)

Anne Archibald peridot.faceted at gmail.com
Wed Oct 14 21:09:08 EDT 2009


2009/10/14 Charles R Harris <charlesr.harris at gmail.com>:
>
>
> On Wed, Oct 14, 2009 at 12:43 PM, Anne Archibald <peridot.faceted at gmail.com>
> wrote:
>>
>> Could the basis objects share code in some other way? I don't really
>> see another good approach - for example I don't see how your
>> loose-functions-plus-class-maker would handle the issue of power(),
>> which is generic for some implementations but specialized in others. I
>> expect roots() to be the same.
>>
>
> I think we should look at Josef's suggestions of metaclasses also.



>> Joking aside, this really is applying your technique to my preferred
>> structure of polynomial object plus basis object. I think there's a
>> real need for a basis object, and if you want to be able to create one
>> simply by specifying a handful of low-level functions, this will do it
>> for you.
>>
>
> I don't like the idea of passing the basis into the instance constructor, I
> think it would be preferable to pass it into the constructor of a class
> creator. That is why Josef's suggestion of a metaclass rouses my curiosity.
> Now if I can only figure out what metaclasses are...

I think passing it to the constructor is kind of a side issue (as I
said, users are never supposed to call the constructor); if I
understand correctly, what you're objecting to is the fact that every
polynomial has a .basis attribute that points to the basis its
coefficients represent.

Certainly every polynomial needs to know what basis it is in, and many
users will also need to know. But it would be possible to create a
class for every different basis and store the basis object in the
class, so that a polynomial contains only its coefficients and a
pointer to its class. Then you could extract a polynomial's basis by
doing, say, mypoly.__class__.basis. Apart from the ugliness of doing
this, I find it rather unpleasant to have potentially thousands of
class objects floating around - remember PowerBasis(0) is different
from PowerBasis(0.32). Also, you have to do some careful work to check
polynomial compatibility: people can, and often will, create different
basis objects that represent the same object. Either you need to
implement a flyweight pattern for your basis objects (or classes -
ugh), or you need to have a way of detecting when two polynomials with
different classes are actually compatible (because the Basis objects
used to manufacture the classes are equal but not the same object).

It just seems simpler to me to have the basis as a full-fledged
attribute of the polynomial class. Given that polynomial classes are
supposed to be immutable, that means it has to be passed in the
constructor.

As for metaclasses, well, in older versions of python if you took an
object's __class__ you got an object representing the object. It
mostly bundled together a bunch of methods, most notably the
constructor for instances. But the type of this object was always the
same. Metaclasses let you use a different type for this object
representing the type of an instance. For example, if you wanted every
class someone defined to be registered in some central registry, you
could make a metaclass that upon instantiation registered itself. Then
every time someone created a new class whose metaclass was this, the
new class would be registered. It allows you to effectively change the
behaviour of the "class" statement. For a sillier example, if you
wanted, for some reason, to have classes print "spam" when asked for
the value of an undefined class method instead of raising an
exception, you'd just make sure the classes used a metaclass that
fabricated class objects that did that. For a more concrete example,
metaclasses can be used to prevent you from instantiating an abstract
base class without providing implementations for all the abstract
methods. It does this by changing the way class objects are made.

I have to say, though, that an implementation that is hard to
understand won't be very friendly to maintainers or users of the
package. And metaclasses and class-producing functions are straying
dangerously into that territory. Limited though inheritance is, it is
at least a very standard well-understood way of sharing code in
python.

>> I should also say that, having implemented KroghInterpolator and
>> BarycentricInterpolator - polynomial objects in fact, albeit with a
>> different goal and very limited features - it's really not difficult
>> to write fast compiled code in cython that works in an object-oriented
>> way.
>
> Yes. Although I expect the bottlenecks are few and those few can be pure C
> (cython) code while the rest is just plain old python. Which cython will
> compile also, of course ;)

And the important speedups will be algorithmic - caching the weights
in a barycentric interpolator reduces evaluation from O(degree**2) to
O(degree), for example. I haven't done this yet because I want to hash
out the interface before I start having too much code to shovel
around.

Anne



More information about the SciPy-Dev mailing list