In a message of Sat, 18 Mar 2006 14:11:03 EST, Arthur writes:
-----Original Message----- From: edu-sig-bounces@python.org [mailto:edu-sig-bounces@python.org] On Behalf Of Arthur Sent: Saturday, March 18, 2006 1:39 PM To: 'Scott David Daniels'; edu-sig@python.org
I don't understand, really, the distinction between a vector expressed as a list and a vector expressed as a tuple, from the concept of a complex number in mutable form, and one in immutable form.
If you feel like trying to help...
Put another way, if I take the PyPy implementation of the complex primiti ve, and comment out the 2 property lines that restrict the write to real and imag - and instead of calling it a primitive I call it a class. And I use the class as such - where have I gone wrong?
Art
I'm confused too. It sounds to me that you want to invent your own type. Does your type have any relationship to the complex numbers that we know and love, or do you just want a type that has 2 parts? In particular, check out: http://home.scarlet.be/~ping1339/complget.htm#Polar-representation Do you want this a + ib = r (cos(t) + i sin(t)) to be true for your type as well? I think so. I'm worried that when you start mutating the type -- as opposed to simply assigning new values to it -- you can create a state where this is _not_ true. Am I wrong? Laura
-----Original Message----- From: Laura Creighton [mailto:lac@strakt.com] Sent: Saturday, March 18, 2006 3:01 PM To: Arthur
I'm confused too.
It sounds to me that you want to invent your own type. Does your type have any relationship to the complex numbers that we know and love, or do you just want a type that has 2 parts?
In particular, check out: http://home.scarlet.be/~ping1339/complget.htm#Polar-representation
Do you want this
a + ib = r (cos(t) + i sin(t))
to be true for your type as well? I think so.
From the use case point of view, I have retained my own skepticism, as I
Isn't the creation of any class the creation of one's own type? Now what am I missing now? My class - unless I am missing something else - does complex mathematics exactly as does the built-in type. But it is now the Complex type, say. Which allows me to say a=Complex(5,3) on creation, and a.real = 6 somewhere down the line. Obviously notation ally, a=5 +3j will still return the Python immutable built-in type. Which is fine by me. That's exactly why I am having so much trouble with the problem I seem to be causing here. I understand next to nothing about threading, but can't understand why this particular class is any less safe than any other class one might create and use. Use cases? Seems to me to be a totally separate and different issue. One that, for example, Michael was skeptical about from the beginning. But that really doesn't seem to me to be what the discussion has been about - at least the discussion that others seem to want to have. tried to make clear. I had my reasonable reasons to go in that direction, I think. But there wasn't any really, really deep soul searching, precisely because there didn't seem to be anything at all unusual about the idea of this kind of class compared to others I might create and use as a matter of course - despite that there was a similar built-in. But no, *don't* like to give up performance, and have been happy to have had a discussion that led me to a possible alternative that is prettier, *and* faster. Ain't Edu-sig cool ;) Art
Arthur wrote:
... Isn't the creation of any class the creation of one's own type? Now what am I missing now?
Ahh, I thought we were talking about language primitives. The range of behavior for non-primitives is larger. For example, a Vertex in 3-space for a polyhedron might have mutable x, y, and z properties just so that shared points and coincident points are distinguished.
My class - unless I am missing something else - does complex mathematics exactly as does the built-in type. But it is now the Complex type, say. Which allows me to say a=Complex(5,3) on creation, and a.real = 6 somewhere down the line. Obviously notation ally, a=5 +3j will still return the Python immutable built-in type. Which is fine by me. I thought you had been asking why it was wrong to make a primitive mutable.
That's exactly why I am having so much trouble with the problem I seem to be causing here. I understand next to nothing about threading, but can't understand why this particular class is any less safe than any other class one might create and use. It is not, except for one thing: one often thinks of complex numbers as values, and when they are mutable, they are more objects than values. It is dangerous in that users of the type may have wrong intuitions.
...But no, *don't* like to give up performance, and have been happy to have had a discussion that led me to a possible alternative that is prettier, *and* faster. OK, so one big performance gain is that immutable values can be safely shared, a copy is never a meaningful operation on an immutable type.
--Scott David Daniels Scott.Daniels@Acm.Org
-----Original Message----- From: edu-sig-bounces@python.org [mailto:edu-sig-bounces@python.org] On Behalf Of Scott David Daniels
Arthur wrote:
... Isn't the creation of any class the creation of one's own
type? Now
what am I missing now? Ahh, I thought we were talking about language primitives.
I guess I have the advantage that this is abstract to everybody else, quite concrete to myself as the class we are talking about is created, in use, and doing its thing. And it is possible - just possible - that people who have never had use for this kind of class might not have ever created dynamic, graphical applications of just the PyGeo kind. Not surprising, because not many people have. Maybe for good enough reason- but that's a separate issue. What was "creepy" - *I thought* - was the concept of mutable complex number as a type, in the same sense that any class is a type. Because what else could we be talking about, since I am designing only an application, not a programming language. And if the consensus now needs to shift to one that I am amateurishly out-of-my-mind to think that this could quite reasonably be a serviceable class *for just the kind of application on which I happen to be working* - let-it-be-so.
It is not, except for one thing: one often thinks of complex numbers as values, and when they are mutable, they are more objects than values.
I am not designing a programming language, I am designing an application. And bingo - for that application I need them to be more objects than values. Art
-----Original Message----- From: edu-sig-bounces@python.org [mailto:edu-sig-bounces@python.org] On Behalf Of Arthur
What was "creepy" - *I thought* - was the concept of mutable complex number as a type, in the same sense that any class is a type.
Just so that I am not accused of being disingenuous. That subject of primitive type was raised early in the discussion, but only intended in the context of the fact that Numeric arrays were prepared to except the immutable built-ins as complex numbers and unprepared to accept the custom class that was the same but mutable, as such. It presented a practical problem to me, and I was looking for practical solutions to it beyond the one had I been working with but found not fully satisfactory. But to repeat - The course of these discussions had some real practical value to me, having helped me come upon an idea for the implementation of the objects of the complex plane geometric objects that I think better reflects the ground of the mathematical ideas being explored, and with less of a performance trade-off. I could not want more, and I just hope I am not missing anything important by being excited about getting to the implementation. The small problem at the moment being the laptop on which I have my latest working version ain't taking well to getting powered up. ARGHHHH., Art
Arthur wrote:
.... The small problem at the moment being the laptop on which I have my latest working version ain't taking well to getting powered up.
ARGHHHH., Laptops are, in my experience fragile little beasties.
So, this discussion has led me to think about a structure like: import numarray class PointHolder(object): def __init__(self): self.points = numarray.array((0., 0., 0.)) self.nextalloc = 0 def new(self, point): if self.nextalloc <= self.points[0]: self.points.resize(((self.points.shape[0] * 2,) + self.points.shape[1:])) result = self.nextalloc self.points[result] = point self.nextalloc += 1 return result def positions(self, index): return self.points[index] class Vertex(object): positions = PointHolder() def __init__(self, point): self.location = self.positions.new(point) def position(self): seturn self.positions.position(self.location) A Vertex is a point on a polyhedron and it is shared by all of the faces that contain it. The 3-space position of the point is kept remotely in a numarray (or Numeric if you prefer) array named Vertex.positions.points; the position of a particular Vertex is available as a method. The value of such a system is that you can apply a transformation (scale, shift, rotate, ...) to all points in a single matrix operation. The work to do such transformations would be proportional to the number of distinct vertices, rather than to the number of mentions in such structures as faces making up a polygon. What got me thinking about this was "why would you want to share mutable state on complexes (and then on points)" -- the answer is when you are applying a uniform transformation to a bunch of points. --Scott David Daniels Scott.Daniels@Acm.Org
-----Original Message----- From: edu-sig-bounces+ajsiegel=optonline.net@python.org [mailto:edu-sig-bounces+ajsiegel=optonline.net@python.org]
On Behalf Of Scott David Daniels
What got me thinking about this was "why would you want to share mutable state on complexes (and then on points)" -- the answer is when you are applying a uniform transformation to a bunch of points.
A lot of what I am doing is about uniform transformations on bunches of points - so I will be looking carefully at the idea you are presenting. To some extent it has been almost scary how straight forward what I am trying to do can be expressed/implemented in Python. Understanding what __iter__, combined with duck typing, can get me in terms of what I am trying to express was the most recent major revelation. Art
The following, modulo a pronoun shift were exactly the words I was sitting down to type.
I am not designing a programming language, I am designing an application.
That is why, to me, the advice offerred to date seems quite far off the mark.
And bingo - for that application I need them to be more objects than values.
So, is there a problem with wrapping them thus: ### class mcx(object): def __init__(self,val): self.val = complex(val) def __add__(self,other): """ and similarly for most other special methods """ return self.val.__add__(other) ### I think Arthur would duckishly call this a mutable complex type and others would more formally call it an object containing a reference to an immutable complex type and we could all live happily ever after. If I am right then the vast verbiage expended on this thread so far deflates into exactly nothing. If this is inadequate for anyone, what exactly is the problem? mt
-----Original Message----- From: edu-sig-bounces@python.org [mailto:edu-sig-bounces@python.org] On Behalf Of Michael Tobis objects than values.
So, is there a problem with wrapping them thus:
### class mcx(object):
def __init__(self,val): self.val = complex(val)
def __add__(self,other): """ and similarly for most other special methods """ return self.val.__add__(other)
###
I think Arthur would duckishly call this a mutable complex type and others would more formally call it an object containing a reference to an immutable complex type and we could all live happily ever after.
Not so easy, I'm afraid. If I am understanding correctly the implementation that you are suggesting is exactly the one I had one generation ago. Kind of the UserArray solution. No? And I can't easily explain why I felt the need to push it a step further - to in fact having a more truly full implementation of complex numerics contained *as* my object - not as an attribute of it. But there were reasons. Some more practical, more less. Art
And I can't easily explain why I felt the need to push it a step further -
Do give it a try, please.
to in fact having a more truly full implementation of complex numerics contained *as* my object - not as an attribute of it. But there were reasons. Some more practical, more less.
Well, if you do it right, the enclosing code would not be different from that of a "truly full" implementation. That's why we use objects in the first place! The rest of the code should need no information about how you implement your mutable complex type. So unless there's a performance issue I can't see what you lose by wrapping the complex number. mt
-----Original Message----- From: Michael Tobis [mailto:mtobis@gmail.com]
So unless there's a performance issue I can't see what you lose by wrapping the complex number.
My last friend ....oh well. Because it didn't *feel* yet that I couldn't come up with something better, that I was at the end of the road. No question, it was workable - and if I was being paid to do this work by the hour it would have been some form of sin to look further. But I'm not. ;) Art
-----Original Message----- From: Arthur [mailto:ajsiegel@optonline.net]
Because it didn't *feel* yet that I couldn't come up with something better, that I was at the end of the road. No question, it was workable - and if I was being paid to do this work by the hour it would have been some form of sin to look further. But I'm not.
I bit more to the point, is I that I consider it an API issue, but an API issue specific to the intent of PyGeo - and that is to allow people to use and extend it as much as possible thinking as geometers and mathematicians and math students rather than as programmers. And there seemed to me something much more natural about saying- think of this *as* a complex number rather than think about wrapping something within a something else. These kinds of API issues, tied to the program's intent, are - IMO - necessary soft, and folks can disagree about what works. I decided this was serious enough not only to make the effort to implement, but to sacrifice performance on its behalf. Judgment call. Art
-----Original Message----- From: Arthur [mailto:ajsiegel@optonline.net]
These kinds of API issues, tied to the program's intent, are - IMO - necessary soft, and folks can disagree about what works. I decided this was serious enough not only to make the effort to implement, but to sacrifice performance on its behalf.
And maybe even more to the point than that - since this is the way that *I* was thinking about these objects - I wanted my conception of the object and their implementation to be as closely and purely allied as possible. With the instinct that doing so would lead me to where I should be going next. Which I think it has. Not textbook, to be sure. Art
Well, if you are sacrificing performance, what is wrong with wrapping the complex number in a pure python class with all the magic methods overridden? I share your objectives and agree that Python provides a platform for addressing them. See my article at http://geosci.uchicago.edu/~tobis/ciseps.pdf You do not explain why a properly duck-typed pure Python wrapper of a complex number fails to achieve those objectives in your case. Calling it an "API" issue appears to me to miss my point. You can present the identical API with a wrapper as with a native extension, and stay out of the mathematician's way altogether, no? If not, why not? Note that when you stray from pure python you shrink your user base and complicate your support issues substantially. I would be happy to discuss the topic, but this requires that I approach the design with due skepticism. If you don't care to explain your needs you can't expect many useful answers, though I think it's reasonable to expect fewer and shorter non-useful ones! Michael
-----Original Message----- From: Michael Tobias [mailto:mtobis@gmail.com]
I would be happy to discuss the topic, but this requires that I approach the design with due skepticism. If you don't care to explain your needs you can't expect many useful answers, though I think it's reasonable to expect fewer and shorter non-useful ones!
I sincerely appreciate your offer, and there is good reason to believe that you have a good beat on my objectives. But as I say, these conversations have actually caused me to reconceptualize a bit. So that talking about my complex "object"'s issues in its specifics seems to address where I was at the beginning of the conversation rather than where I am at the moment. I will have a better idea as to where I am at the moment if the power supply to my laptop decides to begin talking to my laptop. That and a day or two to futz, and than I'd love to reconvene. Art
-----Original Message----- From: Michael Tobis [mailto:mtobis@gmail.com]
You can present the identical API with a wrapper as with a native extension, and stay out of the mathematician's way altogether, no? If not, why not?
Well, instead of arguing what is not optimum about the solution that I *think* you are suggesting I will argue what is - only because I think it brings me around in full circle - I *think* - to where I started. The wrapper allows me to maintain object identity when working within complex typed Numeric arrays, since it is an object attribute been sent and received from the arrays, not the object itself. The solution that I have been exploring is more fragile in this respect. Since Numeric will not accept my complex object as such, and I need to cast it to a complex built-in on the way into the array and back to a complex custom type on the way. My object identity is lost. This is not a killer under my present structure, but is certainly has a more fragile feel that I would like. But in my mind it is only because in moving into Numeric land I am moving out of a land of duck typing and into a land of strict typing. Its Numeric's fault, not mine ;). I was hoping for some elegant solution to this particular issue that is not obvious to me. The other answer is that I should not attempt to fight Mother Nature in this regard. Art
From: Michael Tobis [mailto:mtobis@gmail.com]
Note that when you stray from pure python you shrink your user base and complicate your support issues substantially.
Haven't had the opportunity to code much anew, but am still replaying to myself where I am with these issues, and in the context of the discussion. When Kirby mentioned that he was not using Numeric for the purposes of his pedagogical approach to programming and numerics, I said - right on, why would you unless it was necessary. More transparency. And so realizing that a) my objectives are most fundamentally pedagogical b) Numeric is not playing nice with me at the moment c) I am only using 1% of the capacity of Numeric to do heavyweight array processing d) When I look into the code that Numeric needs to use to talk to - say - laplack, we begin to approach *my* definition of creepy. e) """Note that when you stray from pure python you shrink your user base and complicate your support issues substantially.""" For example, numpy's documentation is not free, at the moment. I am of course thinking whether I have been knee-jerk in bringing Numeric into play as a fundamental tool for my application. Which I why I then move on to trying to get serious about gaining some profiling skills. Gain some intelligence about the trade-offs of doing the kind of simple linear algebra my application requires in pure Python, versus what I may gaining by the creepy calls to laplack. Judgment calls need to be made in the end, but I take them seriously enough to want them to be informed judgment calls. No conclusions as yet. Art
I use numeric a lot, and I understand what you mean. Perhaps there is some Python-like scientific language yet to be invented, but on the other hand, perhaps the interface between convenient latent typing and efficient strong typing may be fated to always be a bit uncomfortable. Meanwhile I have been (rather irresponsibly) obsessed with the idea of a mutable complex. It turned out to be harder than I expected but I learned a lot in the process. Even though I'm still not sure it's a useful idea, I am ready to do it in a rather pretty way, but it will take a couple of hours I'm not sure I have. If you want to beat me to the punch read this thread (if you dare): http://mail.python.org/pipermail/python-list/2006-March/331842.html mt
-----Original Message----- From: Michael Tobis [mailto:mtobis@gmail.com] Sent: Tuesday, March 21, 2006 12:18 PM To: Arthur; edu-sig@python.org Subject: Re: [Edu-sig] Properties use case If you want to beat me to the punch read this thread (if you dare):
http://mail.python.org/pipermail/python-list/2006-March/331842.html
I dared. And it is amazing to me how quickly my eyes glaze over - how unintelligent I am about certain coding issues/styles. I'd would just as soon spell out the magic, method by method - if that is all we are trying to avoid. More typing, maybe a little more time - but once it's there it's there, like forever. 3 hours/float(forever) = 0, approximately. Unless I am misinterpreting what we are trying to do with the nested defs and whatever the hell else is going on in there. The PyPy complex number implementation was the basis for what I ended up with. http://codespeak.net/svn/pypy/dist/pypy/module/__builtin__/app_complex.py As it happens I need a good deal more in terms of methods for my Complex than the "conjugate" that is essentially it for the Python built-in. What other methods, which need to be inplace transformations, and which need to return new Complex objects, or even scalar values - the answers were all pretty specific to my app, not choices I could (or need to I don't think) justify on the basis of any general principles I can identify. Art
On Tue, 2006-03-21 at 11:57 -0500, Arthur wrote: [snip]
I am of course thinking whether I have been knee-jerk in bringing Numeric into play as a fundamental tool for my application.
Which I why I then move on to trying to get serious about gaining some profiling skills. Gain some intelligence about the trade-offs of doing the kind of simple linear algebra my application requires in pure Python, versus what I may gaining by the creepy calls to laplack.
Judgment calls need to be made in the end, but I take them seriously enough to want them to be informed judgment calls.
I've been wrestling with these issues. I've built a Python robotics 2D simulator in 99% Python, 1% Numeric. It works amazingly well: fast enough and realistic enough to do the job. The robot can have sonar, IR, and bumpers; lights, and light bulbs; a 2D camera with pan-zoom, and a gripper to pick up things. The world has some simple physics (bump a puck head-on and it will slide, with some friction). Then I extended it to be a 3D simulator. Still, amazingly, fast enough and realistic enough to do the job. On the one hand, I like all of the source code to be accessible to the student. We say that it is "Pythons all the way down". And that also makes it portable. But on the other hand, it has to run fast enough. We are able to do it all in Python, expect for the nitty gritty vision and image processing code, which we use SWIG and C++. I did some profiling, and was surprised at where some of the time was spent. (This simulator is also controlled over sockets, so I had some additional items to speed up). But, was able to refactor some, and get some very substantial speedup, just in the Python portion. castRay() is still the most expensive bit in Python. I am also looking at IronPython for .NET and Mono, and am wondering how much I can get in one layer (without going to C/C++) and how fast it will be... Here are some pictures: http://pyrorobotics.org/?page=The_20Pyrobot_20Simulator -Doug
No conclusions as yet.
Art
_______________________________________________ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
-- Douglas S. Blank Computer Science Assistant Professor Bryn Mawr College (610)526-6501 http://cs.brynmawr.edu/~dblank
On Saturday 18 March 2006 16:39, Michael Tobis wrote:
So, is there a problem with wrapping them thus:
### class mcx(object):
def __init__(self,val): self.val = complex(val)
def __add__(self,other): """ and similarly for most other special methods """ return self.val.__add__(other) ###
This reminds me of a question I have with new-style classes. With classic Python classes, we can do something like this even more simply with getattr magic: class Mutable: def __init__(self, value): self.value = value def __getattr__(self,name): return getattr(self.value, name) This saves me the trouble of having to specifically reimplement all of the methods just so that I can trivially pass the work off to self.value. Everything works just fine:
from mutable import Mutable x = Mutable(3+5j) x (3+5j) x + (4+7j) (7+12j) print x (3+5j) x.value = 3 x + 4 7
I've used this technique to good advantage when mixing objects from different toolkits. My question is, is there an easy way to do this with new-style classes? While I'm on the thread, let me just add my 2 cents on Arthur's "creepy" mutable complex type. I understand all of the arguments about the potential pitfalls of mutable types (I'm one of those "CS types," don't you know :-). But OOP is all about mutable objects. As a _design_ decision, if a mutable complex will streamline my system, or make it more intuitive, then I wouldn't hesitate to do it. I think the "creepiness" here is just in the name. We don't expect complex numbers to be mutable. Let's call the new type a complex container with auto-unboxing. Does anyone object to a mutable container? I hope not, we used to just call them variables. Since the contents are isomorphic to complex, it could be handy to have the container object also duck-type to a complex (or whatever else it contained). I don't see any creepiness in that. Of course, this kind of thinking could get out of hand. The next thing you know people might use these to simulate wacko things like reference parameters (oh, the horror! :-) Just my 2 cents. --John -- John M. Zelle, Ph.D. Wartburg College Professor of Computer Science Waverly, IA john.zelle@wartburg.edu (319) 352-8360
participants (6)
-
Arthur
-
Douglas S. Blank
-
John Zelle
-
Laura Creighton
-
Michael Tobis
-
Scott David Daniels