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

Anne Archibald peridot.faceted at gmail.com
Tue Oct 13 21:24:09 EDT 2009


2009/10/13 Charles R Harris <charlesr.harris at gmail.com>:
>
>
> On Tue, Oct 13, 2009 at 5:55 PM, Anne Archibald <peridot.faceted at gmail.com>
> wrote:
>>
>> 2009/10/13 Charles R Harris <charlesr.harris at gmail.com>:
>> >
>> >> I'm not sure I see why returning all those NotImplementedErrors is a
>> >> problem - yes, the code needs to be written to override the methods
>> >> that return NotImplementedError, but that code needs to be written no
>> >> matter how we set up an interface to it.
>> >
>> > It's not trivial to do a complete workup. My template class is 698 lines
>> > long, but it exists once in one place, and that does the trick for *all*
>> > the
>> > classes.
>>
>> Aha. I think I see where the confusion is. In my proposed interface,
>> the coefficient-oriented functions would *be* the ones in the Basis
>> object. So, for example,
>>
>> chebadd(c1,c2,interval) -> ChebyshevBasis(interval).add(c1, c2)
>>
>> or, more likely, you'd have somewhere earlier
>>
>> cheb = ChebyshevBasis(interval)
>>
>> and then it's
>>
>> chebadd(c1,c2,interval) -> cheb.add(c1,c2)
>>
>> So the coefficient-oriented interface that we need to have is what
>> lives in the basis objects, and it is what the Polynomial object uses
>> to implement (e.g.) p1*p2. There would be no separate chebmul,
>> polymul, lagrangemul, ....
>>
>
> But the separate functions are what we want. They provide the most flexible
> low level implementation and make the fewest assumptions as to what the
> programmer might want to use them for. You don't really have a base class,
> you essentially have classes derived from different base classes, which
> isn't so different from what I am proposing.

Do we really want the separate functions, rather than methods on a
basis object? Why? I don't really see how they're more flexible or
make fewer assumptions, and they become very cumbersome (and prevent
some important optimizations) when working with polynomials in the
Lagrange basis. It really can be the difference between chebadd(...)
and cheb.add(...), in the (common?) case where people aren't
specifying the interval. And if people do want to specify the
interval, using a basis object makes it much easier to avoid
forgetting it and getting nonsensical results (or worse, sensible
results until you try a different interval).

In this respect, the current interface in chebyshev.py looks
error-prone to me: you can't suppy an interval to chebadd and chebmul,
but if you forget it for chebval you get bogus answers. (And in fact
chebint and chebder are wrong, or at least misleading, if you use a
different interval.)

I'm not sure what you mean when you say I don't really have a base
class: Basis is literally the base class for all Basis objects, and it
provides nontrivial functionality (e.g. the power implementation) that
would otherwise need to be repeated for each representation.
Polynomial is the base class for all polynomials.

>> The Basis object is effectively just a namespace holding the
>> collection of functions, and possibly any data they need (interval,
>> for example). So the separation you're describing is still present in
>> my proposed interface; it's the separation between Basis objects
>> (which contain the functions but no particular plumbing) and the
>> Polynomial objects (which are all plumbing).
>
> Why not let the module hold the functions? It is the more natural namespace
> for python.

Because there is important context - intervals, lists of specified
points - that must be provided to all the coefficient-array functions.
And collections of methods on objects are very natural in python.

>> > In [4]: x + [0]
>> > Out[4]: array([0, 1, 2])
>>
>> This is a special case anyway - it's one of the very few instances in
>> which you can add coefficients the way you're describing. Normally you
>> have to extend one or the other so that they're the same length (and
>> in some bases this is a non-trivial operations, rather than simply
>> padding with zeros). If what you mean here is to add a scalar, there's
>> no reason to wrap it in a list;
>
> Consistency. Usually these things are thought of as algebras with a unit
> over the scalars.

I'm not sure I understand this - consistency with what? It is only
scalars you can reasonably add to coefficient arrays by wrapping in a
list; other coefficient arrays must be the same length as the other
(array) summand or they will fail. And scalars work just as well
without wrapping in a list, so why do it?

Anne

P.S. the current version on github now has the code in the Basis
objects, so that their methods can be used to operate on coefficient
arrays, and added a file demonstrating this use. -A



More information about the SciPy-Dev mailing list