AsyForGiNaC - an output extension producing Asymptote files
Hi! For the last months I worked, inspired by Vladimir Kisil, on an output extension for GiNaC to plot functions with Asymptote. Now the first version is published as a stand-alone library. My intention is to include the functions to the GiNaC library. The design is already focused on a later implementation as part of the GiNaC library. Please have a look. Tarball and Documentation can be found at <http://www.maths.leeds.ac.uk/~kisilv/asyforginac> http://www.maths.leeds.ac.uk/~kisilv/asyforginac. I would be glad to get some feedback. Greetings, Daniel.
Dear Daniel, Daniel Seidel schrieb:
Now the first version is published as a stand-alone library.
My intention is to include the functions to the GiNaC library. The design is already focused on a later implementation as part of the GiNaC library.
Please have a look. Tarball and Documentation can be found at http://www.maths.leeds.ac.uk/~kisilv/asyforginac.
I would be glad to get some feedback.
there was already some discussion about it between Chris and Vladimir on this list some months ago and after looking at Asymptote and your code/doc I have to admit that I share some concerns with Chris about the inclusion of such code into GiNaC. GiNaC is mainly about algebra with some (large) admixture of numerics. The current output system reflects this: It simply converts algebraic expressions into some line-oriented text, nothing more. Almost none context information is needed for that conversion, so it fits well with the OOP paradigm to let the printing facility be part of the GiNaC classes themselves: Every object/algebraic expression is asked to print itself. With graphical drawing this seems not to be the case. One needs to give numerical ranges for example to the output facility (in most cases). It is (almost) always like "draw(Object, Numerical Range, XYZ Spec)". The bottom line here is, that with graphics there are two possible ways to do it: as part of the classes or outside of them. A priori, none is preferable. But putting them inside the classes has one obvious disadvantage: the code base gets more complex and dependent on other software. And I don't like the idea of having classes that sport say 10 methods for the usual GiNaC stuff and then 10 additional methods just for drawing ... looks like somebody missed the point. So, the question is: what are the advantages and do they outbalance the mentioned disadvantage? I read the remarks in your doc about certain advantages but the details are not clear to me. Have you thought about using some of the visitor-stuff in GiNaC, yet? Regards, Jens
Dear Jens,
"JV" == Jens Vollinga <vollinga@physik.uni-wuppertal.de> writes:
JV> GiNaC is mainly about algebra with some (large) admixture of JV> numerics. Some people like algebraic expressions to be visualised, e.g. gTubalt enriches GiNaC by drawing facilities from Root and everyone seems to like it. JV> And I don't like the idea of having classes that JV> sport say 10 methods for the usual GiNaC stuff and then 10 JV> additional methods just for drawing The idea is to add one more printing context "asy" to the "text", "latex", "python", etc. family. JV> most cases). It is (almost) always like "draw(Object, Numerical JV> Range, XYZ Spec)". Note that here "Numerical Range" and "XYZ Spec" are properties of the scene, not of "Object". Thus there is no need to store all drawing option in the Object. Rather you may prepare an Asymptote scene with required properties and then ask one or several GiNaC objects "print_asy" themselves on this scene. A beautiful drawing is always uneasy and will require a lot of customisation. However it will nice if GiNaC will have at least basic possibility to draw a graph of function. It became even more true with development of several interactive wrappers. Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk -- www: http://maths.leeds.ac.uk/~kisilv/
Dear Vladimir, Vladimir Kisil schrieb:
Dear Jens,
"JV" == Jens Vollinga <vollinga@physik.uni-wuppertal.de> writes:
JV> GiNaC is mainly about algebra with some (large) admixture of JV> numerics.
Some people like algebraic expressions to be visualised, e.g. gTubalt enriches GiNaC by drawing facilities from Root and everyone seems to like it.
agreed! The only concern I've expressed is whether to have this drawing facility be part of the GiNaC classes or not.
JV> And I don't like the idea of having classes that JV> sport say 10 methods for the usual GiNaC stuff and then 10 JV> additional methods just for drawing
The idea is to add one more printing context "asy" to the "text", "latex", "python", etc. family.
Ah, that is something I was not aware of. I thought that there should be draw, draw_like_this, draw_the_other_way methods added to the classes. So, is it just a new printing context?
JV> most cases). It is (almost) always like "draw(Object, Numerical JV> Range, XYZ Spec)".
Note that here "Numerical Range" and "XYZ Spec" are properties of the scene, not of "Object". Thus there is no need to store all drawing option in the Object. Rather you may prepare an Asymptote scene with required properties and then ask one or several GiNaC objects "print_asy" themselves on this scene.
So, this preparation is done in some global object and later when the GiNaC objects are asked to print themselves they in turn ask (in case the asy printing context is used) this object for certain properties? Is this the plan, roughly?
A beautiful drawing is always uneasy and will require a lot of customisation. However it will nice if GiNaC will have at least basic possibility to draw a graph of function. It became even more true with development of several interactive wrappers.
True. Regards, Jens
Dear Jens,
"JV" == Jens Vollinga <vollinga@physik.uni-wuppertal.de> writes: >> The idea is to add one more printing context "asy" to the "text", >> "latex", "python", etc. family.
JV> Ah, that is something I was not aware of. I thought that there JV> should be draw, draw_like_this, draw_the_other_way methods added JV> to the classes. So, is it just a new printing context? Since Asymptote is command-driven language we only need "print" suitable instructions, the drawing will done for us. JV> So, this preparation is done in some global object and later JV> when the GiNaC objects are asked to print themselves they in JV> turn ask (in case the asy printing context is used) this object JV> for certain properties? Is this the plan, roughly? This is indeed the idea (unless something better will be suggested). I also suppose that basic GiNaC abilities in this respect should be very modest, but a user should be able to modify/extend them easily for specific needs/derived classes. After all even a standalone library is already useful. But we still have not got a place to put "Contrib" stuff.... Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk -- www: http://maths.leeds.ac.uk/~kisilv/
Dear Jens, Am Mittwoch, den 16.08.2006, 18:40 +0200 schrieb Jens Vollinga:
Dear Vladimir,
Vladimir Kisil schrieb:
Dear Jens,
> "JV" == Jens Vollinga <vollinga@physik.uni-wuppertal.de> writes:
JV> GiNaC is mainly about algebra with some (large) admixture of JV> numerics.
Some people like algebraic expressions to be visualised, e.g. gTubalt enriches GiNaC by drawing facilities from Root and everyone seems to like it.
agreed! The only concern I've expressed is whether to have this drawing facility be part of the GiNaC classes or not.
JV> And I don't like the idea of having classes that JV> sport say 10 methods for the usual GiNaC stuff and then 10 JV> additional methods just for drawing
The idea is to add one more printing context "asy" to the "text", "latex", "python", etc. family.
Ah, that is something I was not aware of. I thought that there should be draw, draw_like_this, draw_the_other_way methods added to the classes. So, is it just a new printing context?
Actually I like to add all these functions. Maybe it's really not necessary and belongs more to the scene, rather than the Object. But the basic idea is: an object gets the description of the scene (where the "like_this" is part of) and than knows how to be drawn, or if it is a more specialized object (maybe a GiNaC::function, or something like the cycle2D class of Vladimirs cycle library, which derives from GiNaC::basic), knows how to adjust the scene itself to a optimised picture. So, what can be done o u t s i d e the object is generating mostly all the scene settings (axis, perspective, import, ...), because it doesn't depend on the object. This is currently done by asy::fnctset and it's derived classes. I n s i d e the object the number field (or maybe a smarter graph) should be produced, because some objects like cycle2D, will know how to produce the graph, while an common method (now knowing only how to draw explicit given things) will fail. Also the object should be able (if wanted by the user) to adjust parameters, if it has knowledge about suitable parameters (therefore the optimize parameter is inserted). This feature will probably only become really meaningful with GiNaC::function objects and objects of classes as specific as cycle2D.
JV> most cases). It is (almost) always like "draw(Object, Numerical JV> Range, XYZ Spec)".
Note that here "Numerical Range" and "XYZ Spec" are properties of the scene, not of "Object". Thus there is no need to store all drawing option in the Object. Rather you may prepare an Asymptote scene with required properties and then ask one or several GiNaC objects "print_asy" themselves on this scene.
So, this preparation is done in some global object and later when the GiNaC objects are asked to print themselves they in turn ask (in case the asy printing context is used) this object for certain properties? Is this the plan, roughly?
yes. A asy::options object stores all "XYZ spec" and than a pointer to this asy::options object is passed to the drawing function of the object to be drawn. I.e. the object can access parameters it has to know and (if the user wishes) manipulate some parameters as well (like described above).
A beautiful drawing is always uneasy and will require a lot of customisation. However it will nice if GiNaC will have at least basic possibility to draw a graph of function. It became even more true with development of several interactive wrappers.
True.
Regards, Jens _______________________________________________ GiNaC-devel mailing list GiNaC-devel@ginac.de https://www.cebix.net/mailman/listinfo/ginac-devel
Dear Daniel, Daniel Seidel schrieb:
agreed! The only concern I've expressed is whether to have this drawing facility be part of the GiNaC classes or not.
JV> And I don't like the idea of having classes that JV> sport say 10 methods for the usual GiNaC stuff and then 10 JV> additional methods just for drawing
The idea is to add one more printing context "asy" to the "text", "latex", "python", etc. family.
Ah, that is something I was not aware of. I thought that there should be draw, draw_like_this, draw_the_other_way methods added to the classes. So, is it just a new printing context?
Actually I like to add all these functions. Maybe it's really not necessary and belongs more to the scene, rather than the Object.
Necessary or not? That's the key issue. If you like to add all these functions then we are back at my initial objections.
But the basic idea is: an object gets the description of the scene (where the "like_this" is part of) and than knows how to be drawn, or if it is a more specialized object (maybe a GiNaC::function, or something like the cycle2D class of Vladimirs cycle library, which derives from GiNaC::basic), knows how to adjust the scene itself to a optimised picture.
This is something I don't really understand yet. Let's say we have an object 'sin(x)'. Now, how does this object know how to draw itself?!? That's only possible if you supply some numerical value for x. And if you supply numerical values, then I see no difference between "let the object draw itself" and "do an evalf from the outside and plot the returned value (also from the outside)" just that the first option leads to a "pollution" of the class interface.
So, what can be done o u t s i d e the object is generating mostly all the scene settings (axis, perspective, import, ...), because it doesn't depend on the object. This is currently done by asy::fnctset and it's derived classes. I n s i d e the object the number field (or maybe a smarter graph) should be produced, because some objects like cycle2D, will know how to produce the graph, while an common method (now knowing only how to draw explicit given things) will fail.
Is there something else involved than using the numerical value of an expression at certain evaluation points? Or to put it differently: what _HIDDEN_ information from GiNaC classes do you actually need for drawing with Asymptote? Regards, Jens
Dear Daniel,
Daniel Seidel schrieb:
agreed! The only concern I've expressed is whether to have this drawing facility be part of the GiNaC classes or not.
JV> And I don't like the idea of having classes that JV> sport say 10 methods for the usual GiNaC stuff and then 10 JV> additional methods just for drawing
The idea is to add one more printing context "asy" to the "text", "latex", "python", etc. family.
Ah, that is something I was not aware of. I thought that there should be
draw, draw_like_this, draw_the_other_way methods added to the classes. So, is it just a new printing context?
Actually I like to add all these functions. Maybe it's really not necessary and belongs more to the scene, rather than the Object.
Necessary or not? That's the key issue. If you like to add all these functions then we are back at my initial objections.
But the basic idea is: an object gets the description of the scene (where the "like_this" is part of) and than knows how to be drawn, or if it is a more specialized object (maybe a GiNaC::function, or something like the cycle2D class of Vladimirs cycle library, which derives from GiNaC::basic), knows how to adjust the scene itself to a optimised picture.
This is something I don't really understand yet. Let's say we have an object 'sin(x)'. Now, how does this object know how to draw itself?!? That's only possible if you supply some numerical value for x. And if you supply numerical values, then I see no difference between "let the object draw itself" and "do an evalf from the outside and plot the returned value (also from the outside)" just that the first option leads to a "pollution" of the class interface.
The function couldn't just produce a number field. It could choose only several point, like lets say in case of 'sin x' every PI interval maybe and connect them with other operators, adjusting tension. This would lead to a smaller output file and less calculation effort. The situation gets more interesting thinking of functions with poles (currently the standard 'tan x' output looks awful) or if you go to things like cycles, being having not a unique value f(x) anymore. I think than it's useful or even necessary to have special information.
So, what can be done o u t s i d e the object is generating mostly all the scene settings (axis, perspective, import, ...), because it doesn't depend on the object. This is currently done by asy::fnctset and it's derived classes. I n s i d e the object the number field (or maybe a smarter graph) should be produced, because some objects like cycle2D, will know how to produce the graph, while an common method (now knowing only how to draw explicit given things) will fail.
Is there something else involved than using the numerical value of an expression at certain evaluation points?
Or to put it differently: what _HIDDEN_ information from GiNaC classes do you actually need for drawing with Asymptote?
"JV" == Jens Vollinga <vollinga@physik.uni-wuppertal.de> writes: JV> Necessary or not? That's the key issue. If you like to add all JV> these functions then we are back at my initial objections.
My personal opinion is that GiNaC should provide basic functionality for drawing AND an easy possibility for a user to extend/redefine the default routines. JV> Is there something else involved than using the numerical value JV> of an expression at certain evaluation points? Yes, Daniel already mentioned that. Eg, since Asymptote uses cubic splines a much better output can be obtained with an enriching evalf() at a mesh points with diff().evalf(). A user should have a freedom to get access to the whole expression and whole GiNaC set of tools to create his own output routines adjusted to specific cases. Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk -- www: http://maths.leeds.ac.uk/~kisilv/
Dear Vladimir and Daniel, I am now halfway convinced that having an specialized Asymptote output might be a good idea. But, one further objection: you both don't seem to agree on whether there should be just another print context or in addition to that several new methods to class basic. Could you give some clarification? From the examples you gave, like tan(x) or cycles, it seems to me that only a new print context is needed. Regards, Jens
"JV" == Jens Vollinga <vollinga@physik.uni-wuppertal.de> writes: JV> But, one further objection: you both don't seem to agree... Could you JV> give some clarification?
This is so far the independent work done by Daniel alone, I only suggested the topic. A wider agreement should be reached for further steps. JV> From the examples you gave, like tan(x) or cycles, it seems to JV> me that only a new print context is needed. I am in favour of printing context with seamless infrastructure for further extensions by users/developers, (eg virtual methods?). JV> whether there should be just another print context or in JV> addition to that several new methods to class basic. Eg it may be a kind of route implemented in power(): the printing context first checks are there any specific drawing methods defined for the given class/defined scene combination and if not---fall back to the default procedure. Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk -- www: http://maths.leeds.ac.uk/~kisilv/
Dear Vladimir, Vladimir Kisil schrieb:
JV> From the examples you gave, like tan(x) or cycles, it seems to JV> me that only a new print context is needed.
I am in favour of printing context with seamless infrastructure for further extensions by users/developers, (eg virtual methods?).
the seamless infrastructure is already there (cf. chapter 6.3 of the manual). The only exception being GiNaC functions at the moment. This could be remedied with the new function classes I am currently experimenting with.
JV> whether there should be just another print context or in JV> addition to that several new methods to class basic.
Eg it may be a kind of route implemented in power(): the printing context first checks are there any specific drawing methods defined for the given class/defined scene combination and if not---fall back to the default procedure.
See 6.3 again. It's already there, as long as it is only about printing Asymptote commands. I have still the impression that different things get mixed-up somehow: GiNaC will _never_ ever DRAW things (unless we link it against OpenGL or something similar ...). And since it doesn't draw anything there is no need for drawing methods. It is a nice idea to have GiNaC produce drawing commands for systems like Asymptote, though. But this is simply PRINTing text in Asymptote syntax, exactly like PRINTing in C or LaTeX syntax. The only thing needed therefore is - at least to me, correct me if I am wrong - a new printing context. New PRINT methods have to be added to GiNaC that have decent defaults. In case the user wants something more special he can use the technique explained in Ch.6.3. If this is correct, then it's okay with me to add such a possibility to GiNaC. Is it correct? Then I have some light concerns about a continuous maintenance of that additional code (we had a similar issue with printing in python format in the past IIRC), but I guess it is something we just have to try. I thought about myself adding some stuff somewhere and then having to worry not just about plain text or LaTeX printing, which I think I can handle, but also about some unfamiliar system (Asymptote) with lots of complexity for which I don't like to invest much time in learning in the near future. Somebody will have to take care of that, continuously. Regards, Jens
"JV" == Jens Vollinga <vollinga@physik.uni-wuppertal.de> writes: JV> GiNaC will _never_ ever DRAW things (unless we link it against JV> OpenGL or something similar ...).
Currently I can use pyGinac interactively to feed through a pipe drawing command to Asymptote and see immediately the result in a GV window, no need to link against any graphic library, popen() is sufficient from GiNaC and Asy does the rest. JV> And since it doesn't draw anything there is no need for drawing methods. OK, let's name them "advanced printing methods" ;-) JV> It is a nice idea to have GiNaC produce drawing commands for JV> systems like Asymptote, though. But this is simply PRINTing text ..... JV> case the user wants something more special he can use the JV> technique explained in Ch.6.3. I support this approach. JV> Then I have some light concerns about a continuous maintenance JV> of that additional code (we had a similar issue with printing in JV> python format in the past IIRC), ... JV> future. Somebody will have to take care of that, continuously. This is why I also ad vacating only straightforward functionality in the core GiNaC with a possibility to have more drawing (sorry, printing ;-) methods possibly in a separate library in the anticipated Contrib storage. Best, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk -- www: http://maths.leeds.ac.uk/~kisilv/
Dear Vladimir, Vladimir Kisil schrieb:
"JV" == Jens Vollinga <vollinga@physik.uni-wuppertal.de> writes: JV> GiNaC will _never_ ever DRAW things (unless we link it against JV> OpenGL or something similar ...).
Currently I can use pyGinac interactively to feed through a pipe drawing command to Asymptote and see immediately the result in a GV window, no need to link against any graphic library, popen() is sufficient from GiNaC and Asy does the rest.
my words ... GiNaC never draws anything :-)
JV> Then I have some light concerns about a continuous maintenance JV> of that additional code (we had a similar issue with printing in JV> python format in the past IIRC), ... JV> future. Somebody will have to take care of that, continuously.
This is why I also ad vacating only straightforward functionality in the core GiNaC with a possibility to have more drawing (sorry, printing ;-) methods possibly in a separate library in the anticipated Contrib storage.
Even if you don't appreciate the difference between drawing and printing yet ;-), it is significant: using all that is described in section 6.3.3 of the manual, no extra code needs to be added to GiNaC then. It could (and probably will) be added to GiNaC, because it spares the user some extra work, but that's the ONLY reason! The statement put forward in the documentation of AsyForGiNaC and in some emails that the output quality or that the possible drawing capabilities can only be increased if the GiNaC classes are altered is not true. Maybe you don't agree with this yet, or maybe I oversee something important, but at the moment I think the discussion is at a dead end, since either we agree on some important points (printing in Asymptote format is useful and code can be added to GiNaC), or we disagree but the issue can only be decided with further coding efforts (to explicitly and clearly demonstrate the case). Regards, Jens
Dear Jens,
Vladimir Kisil schrieb:
> "JV" == Jens Vollinga <vollinga@physik.uni-wuppertal.de> writes: JV> GiNaC will _never_ ever DRAW things (unless we link it against JV> OpenGL or something similar ...).
Currently I can use pyGinac interactively to feed through a pipe drawing command to Asymptote and see immediately the result in a GV window, no need to link against any graphic library, popen() is sufficient from GiNaC and Asy does the rest.
my words ... GiNaC never draws anything :-) [DS]you're right. Lets substitute _draw_ by _print_.
[Jens from like two mails ago] ...The only thing needed therefore is - at least to me, correct me if I am wrong - a new printing context. [DS]Including the functions like 'class print_asy : public print_dflt' is not a good idea, because the fallback goes first down the print_context and so instead of using the basic print_asy it will use a print_dflt output if defined. Bad.
JV> Then I have some light concerns about a continuous maintenance JV> of that additional code (we had a similar issue with printing in JV> python format in the past IIRC), ... JV> future. Somebody will have to take care of that, continuously.
This is why I also ad vacating only straightforward functionality in the core GiNaC with a possibility to have more drawing (sorry, printing ;-) methods possibly in a separate library in the anticipated Contrib storage.
[DS]The current code may be enough for the first time. In case you are planning to add an numerical equation solver to GiNaC some extensions may be good. For the first time I think I could fix bugs, if there are some or adjust the output to upcoming new Asymptote version (I noticed that they change some functions incompatible to old versions while programming with an older Manual then my installed version). Even I have to admit being not a real expert.
Even if you don't appreciate the difference between drawing and printing yet ;-), it is significant: using all that is described in section 6.3.3 of the manual, no extra code needs to be added to GiNaC then. It could (and probably will) be added to GiNaC, because it spares the user some extra work, but that's the ONLY reason! The statement put forward in the documentation of AsyForGiNaC and in some emails that the output quality or that the possible drawing capabilities can only be increased if the GiNaC classes are altered is not true.
Maybe you don't agree with this yet, or maybe I oversee something important, but at the moment I think the discussion is at a dead end, since either we agree on some important points (printing in Asymptote format is useful and code can be added to GiNaC), or we disagree but the issue can only be decided with further coding efforts (to explicitly and clearly demonstrate the case).
[DS] Before producing new code we should agree about the design. I hope we agree about the disadvantage of the print_context fallback. The basic thing that should be possible is to write classes derived from GiNaC::basic and adjust printing options, still keeping the unified interface. If you have a better idea than adding the print methods to GiNaC::basic virtually, I would agree luckily. But I don't know how to do it else. If we agree about this things and there's a probable chance the code is added in a further version I could go on implementing it to GiNaC and maybe Vladimir could use it for the cycle class. To write smart functions for the functions like sin, tan ... will probably be a bit more work and I would delay this a bit (or anyone else wants to do it). One more sentence to adding just one asy_print function or asy_print_like_this, asy_print_else, .... I will think about a solution with one function and a parameter. One's should be able to decide which print is wanted by analysing the parameters (if the parameter will have a default value like 'auto') in most cases. But I assume it will lead to difficult checks in the asy_print function and in some cases it is not decidable (3D function surface or palette?). So that's why I prefer one method per output format. It passes responsibility to the user, for him it should be an easy decision, knowing what he wants. Additionally I was thinking about a method asy_print which doesn't specify the drawing format. This can be useful for things like cycle2D, knowing exactly there best output format. For the implementation in GiNaC::basic it should only call the function printing the label. That's maybe worth some more discussion. Greetings, Daniel.
Dear Daniel, Daniel Seidel schrieb:
[Jens from like two mails ago] ...The only thing needed therefore is - at least to me, correct me if I am wrong - a new printing context. [DS]Including the functions like 'class print_asy : public print_dflt' is not a good idea, because the fallback goes first down the print_context and so instead of using the basic print_asy it will use a print_dflt output if defined. Bad.
currently I am thinking this is good. Maybe I can convince you as well. Let's look at latex format. There you have class print_latex : public print_context In case a class doesn't handle print_latex (some developer was lazy, for example) it defaults to "normal" printing. It doesn't raise an exception. In lots of cases the "normal" output is no valid latex syntax, so the latex interpreter will complain. But still you have the full output. You could load the output in some text editor and fix the output quite easily. If after some long calculation somebody's program starts to print its (often comparatively small) result and just "crashes" with an exception, lots of somebodies would probably be very annoyed. They could file a bug report and wait until somebody fixes the source code (the advanced user may correct the bug(?) for himself, of course). But the aforementioned option to correct the buggy output in some text editor is not possible. Essentially they would have to (wait for help and then to) run their program again. The same is probably true for asymptote output. There you would just get let's say a "sin(x)" for example instead of some more elaborate asymptote code. Either Asymptote will complain or produce bad graphics then. But it is very likely that one is able to fix that afterwards with some search and replace (and then file a bug report, of course).
[DS] Before producing new code we should agree about the design. I hope we agree about the disadvantage of the print_context fallback. The basic thing
Let's say you do something like class print_asy : public print_context class print_asy_differently : public print_asy class print_asy_even_more_advanced : public print_asy then you could define functions like mul_print_asy() add_print_asy_differently() ... at first separately from GiNaC sources (later these functions could be made member functions, NON-VIRTUAL member functions, cf. basic::do_print_tree()), and then gather commands like [weird stuff].print_func<print_asy>(&mul_print_asy) ... in some central source file. By 'at first' I mean 'until the change rate allows for a decent CVS commit schedule'.
that should be possible is to write classes derived from GiNaC::basic and adjust printing options, still keeping the unified interface. If you have a better idea than adding the print methods to GiNaC::basic virtually, I would agree luckily. But I don't know how to do it else.
The code example gives an idea how it can be done. Regards, Jens
Dear Jens, Am Montag, den 21.08.2006, 14:28 +0200 schrieb Jens Vollinga:
Dear Daniel,
Daniel Seidel schrieb:
[Jens from like two mails ago] ...The only thing needed therefore is - at least to me, correct me if I am wrong - a new printing context. [DS]Including the functions like 'class print_asy : public print_dflt' is not a good idea, because the fallback goes first down the print_context and so instead of using the basic print_asy it will use a print_dflt output if defined. Bad.
currently I am thinking this is good. Maybe I can convince you as well.
I agree with you that it is a good idea for the existing output formats, because it's really better if the mathematical expression remains, than printing something like [GiNaC-Object] and I have no doubts about this being a good solution. But, concerning the output for asymptote it will be different. Because usually it should not print only the formula, it should print the description of a graph. So at the end (after processing the output file with Asymptote there should be a picture. The text produced from asy_print is far more then the formula. It is code for Asymptote, which describes how to draw. This produced output doesn't even necessarily have to include the literally written formula, that would be produced from all other print_context. So the code would not be useful at all.
Let's look at latex format. There you have
class print_latex : public print_context
In case a class doesn't handle print_latex (some developer was lazy, for example) it defaults to "normal" printing. It doesn't raise an exception. In lots of cases the "normal" output is no valid latex syntax, so the latex interpreter will complain. But still you have the full output. You could load the output in some text editor and fix the output quite easily. In this case really true.
If after some long calculation somebody's program starts to print its (often comparatively small) result and just "crashes" with an exception, lots of somebodies would probably be very annoyed. They could file a bug report and wait until somebody fixes the source code (the advanced user may correct the bug(?) for himself, of course). But the aforementioned option to correct the buggy output in some text editor is not possible. Essentially they would have to (wait for help and then to) run their program again. why should it crash more often? (just because I don't understand this)
The same is probably true for asymptote output. There you would just get let's say a "sin(x)" for example instead of some more elaborate asymptote code. Either Asymptote will complain or produce bad graphics then. But it is very likely that one is able to fix that afterwards with some search and replace (and then file a bug report, of course). No. See explanation above.
[DS] Before producing new code we should agree about the design. I hope we agree about the disadvantage of the print_context fallback. The basic thing
Let's say you do something like
class print_asy : public print_context class print_asy_differently : public print_asy class print_asy_even_more_advanced : public print_asy
I doubt that this is a good idea, not only because of the fall back, as well because of the parameters handed over. All printing functions have the structure my_print_xxx(const GiNaC::xxx & p, const print_context & c, unsigned level) and the print_contexts are without the parameters needed for the asymptote output.
then you could define functions like
mul_print_asy() add_print_asy_differently() ...
at first separately from GiNaC sources (later these functions could be made member functions, NON-VIRTUAL member functions, cf. basic::do_print_tree()),
and then gather commands like
[weird stuff].print_func<print_asy>(&mul_print_asy) ...
in some central source file.
My new idea, to keep the package as stand alone, but allow all drawing functions adopted to the class was to use templates, like template <class T> void draw_however(std::ostream ostr, T& obj, ...) and specify them like: template <> void draw_however<GiNaC::basic>(std::ostream ostr, GiNaC::basic& obj, ...) template <> void draw_however<GiNaC::basic>(std::ostream ostr, GiNaC::mul& obj, ...) and so on. The problem: all 'obj' are type 'ex'. So it's not working this simple. Has anyone an idea how I could fix this? That would be great and solve the problems of a permanent implementation in the GiNaC library. Ones could simply add it as extra library, if needed. Greetings, Daniel.
Dear Daniel, Daniel Seidel schrieb:
I agree with you that it is a good idea for the existing output formats, because it's really better if the mathematical expression remains, than printing something like [GiNaC-Object] and I have no doubts about this being a good solution. But, concerning the output for asymptote it will be different. Because usually it should not print only the formula, it should print the description of a graph. So at the end (after processing the output file with Asymptote there should be a picture. The text produced from asy_print is far more then the formula. It is code for Asymptote, which describes how to draw. This produced output doesn't even necessarily have to include the literally written formula, that would be produced from all other print_context. So the code would not be useful at all.
you're probably right on this. But now just one question comes to my mind: if this Asymptote output is such complex, isn't the output of one object really independent of all the other? If you have something like x+y (don't take it literally, it is really much too simple an example) and the output method for x produces lengthy Asymptote commands, and after this the output method for y does produce equally lengthy commands, and finally 'add' does the same (how actually?), couldn't it be that these three outputs somehow interfere destructively?? Like x is plotting the coordinate system there, but y wants it somewhere else ... This question has not much to do with our ongoing discussion, I just ask out of curiosity.
If after some long calculation somebody's program starts to print its (often comparatively small) result and just "crashes" with an exception, lots of somebodies would probably be very annoyed. They could file a bug report and wait until somebody fixes the source code (the advanced user may correct the bug(?) for himself, of course). But the aforementioned option to correct the buggy output in some text editor is not possible. Essentially they would have to (wait for help and then to) run their program again. why should it crash more often? (just because I don't understand this)
Not more often. The difference is: programs terminate normally with full output vs. programs terminate abnormally at some point without full output. Exceptions, if not caught, look very much like ordinary program crashes for the user.
I doubt that this is a good idea, not only because of the fall back, as well because of the parameters handed over. All printing functions have the structure my_print_xxx(const GiNaC::xxx & p, const print_context & c, unsigned level) and the print_contexts are without the parameters needed for the asymptote output.
The various asy print contexts can have static variables together with their set/get methods. So, instead of giving some parameters to the printing function you would set your parameters at the beginning with mentioned static methods, and then simply filling the stream: print_asy::set_orientation(90); print_asy::set_size(100,100,20); cout << asy << x+y; Is that possible?
My new idea, to keep the package as stand alone, but allow all drawing functions adopted to the class was to use templates, like
template <class T> void draw_however(std::ostream ostr, T& obj, ...)
and specify them like:
template <> void draw_however<GiNaC::basic>(std::ostream ostr, GiNaC::basic& obj, ...) template <> void draw_however<GiNaC::basic>(std::ostream ostr, GiNaC::mul& obj, ...)
and so on. The problem: all 'obj' are type 'ex'. So it's not working this simple. Has anyone an idea how I could fix this? That would be great and solve the problems of a permanent implementation in the GiNaC library. Ones could simply add it as extra library, if needed.
You'd have to use map functions instead, cf. tutorial sec. 5.5, I guess. Regards, Jens
Dear Daniel, I will be at Uni on Wed and Fri, so you can see me and take your updated certificate. In relation to "printing" methods for Asymptote please consider the example below. In fact a lot of GiNaC expressions may be directly "printed" to Asy without any evaluations at all. Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk -- www: http://maths.leeds.ac.uk/~kisilv/ include <iostream> #include <ginac/ginac.h> #include <ext/stdio_filebuf.h> using namespace std; using namespace GiNaC; int main(){ FILE* s=popen("asy > /dev/null","w"); __gnu_cxx::stdio_filebuf<char> fb(s,ios::out); ostream asy(&fb); realsymbol t("t"), x("z.x"), y("z.y"); ex parabola=pow(t,2), sadle=pow(x,2)-pow(y,2); asy << "import graph;" << "size(200);" << "real f(real t) {return " << parabola << ";}" << "xaxis(\"x\"); yaxis(\"y\");" << "draw(graph(f, -2, 2, operator ..),red);" << "shipout(\"parabola\");" << "erase();"<< endl; asy.flush(); asy << "import graph3;" << "real f(pair z) {return " << sadle << ";}" << "add(surface(f, 10, (-1,-1), (1,1), 10));" << "shipout(\"sadle\");" << endl; asy.flush(); asy << "exit;" << endl; asy.flush(); pclose(s); }
Daniel Seidel wrote:
[DS]The current code may be enough for the first time. In case you are planning to add an numerical equation solver to GiNaC some extensions may be good.
Hmm, don't we already have Newton-Raphson implemented in the fsolve() function? :-) -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
Hello, On Tue, Aug 15, 2006 at 03:39:25PM +0100, Daniel Seidel wrote:
For the last months I worked, inspired by Vladimir Kisil, on an output extension for GiNaC to plot functions with Asymptote.
Frankly, I dislike Asymptote for its home-brew programming language. It would be nice if Asymptote will be just a C/C++ library, or at least provide C/C++ API.
Now the first version is published as a stand-alone library.
My intention is to include the functions to the GiNaC library. The design is already focused on a later implementation as part of the GiNaC library.
In the next version this approach should be included into the GiNaC library. Therefore the stream manipulator method fct() should only call the appropriate draw method implemented virtual in GiNaC::basic.
I don't like adding any virtual methods to GiNaC::basic (actually, I'd like to get rid of some already existing ones). Leaving aside "aesthetical" issues (such an approach is completely anti-OO), adding virtual method costs extra bytes (at least, vtable entry should be stored somewhere) for *every* GiNaC object. With real-world expressions this translates into several hundreds of megabytes of RAM wasted for nothing good. Secondly, drawing is sensible only for small subset of GiNaC classes (can one draw a tensor? a complex-valued function? etc.), so I can't see any point in adding them for *all* classes. Finally, it looks like information available from public interface is enough (so current implementation works). So why do you need to add some methods to GiNaC::basic at all? BTW, I have similar concerns about printing methods. Most of expressions are never going to be printed (except for debugging purposes), so turning printing methods into stand-alone functions would save some non-negligible amount of RAM...
This allows different draw functions for each class derived from GiNaC::basic, respectively.
I think it is better to make this function a template and provide different specializations for derived classes. Now comes some sort of bug report: $ cd example; ./palette successful finished. "palette_std.asy" and "palette_man.asy" have been produced in the subfolder "./output/". Process these files with asymptote:
$ asy palette_std.asy $ asy palette_man.asy
The files "palette_std.eps" and "palette_man.eps" will be produced. $ asy output/palette_std.asy output/palette_std.asy: 42.35: no matching function 'image(picture, real[][], pair, pair, pen[])' asy output/surface_man.asy output/surface_man.asy: 78.4: no matching function 'add(picture, picture, pair)' $ ./surface successful finished. "surface_std.asy" and "surface_man.asy" have been produced in the subfolder "./output/". Process these files with asymptote:
$ asy surface_std.asy $ asy surface_man.asy
The files "surface_std.eps" and "surface_man.eps" will be produced. $ asy output/surface_man.asy output/surface_man.asy: 78.4: no matching function 'add(picture, picture, pair)' I use GiNaC 1.3.5, Asymptote 1.03, g++ 4.1.2 Best regards, Alexei. -- All science is either physics or stamp collecting.
"SA" == Sheplyakov Alexei <varg@theor.jinr.ru> writes: SA> Secondly, drawing is sensible only for small subset of GiNaC SA> classes ... a complex-valued function?....
Yes, complex-valued functions are drawable. SA> I use GiNaC 1.3.5, Asymptote 1.03, g++ 4.1.2 INSTALL recommends Asymptote 1.11 Generally, a couple of recent discussions in this list are derived from the more general question: Is GiNaC a tool for a broad community or it is narrowed to special needs/circumstances? Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk -- www: http://maths.leeds.ac.uk/~kisilv/
Hello, On Sat, Aug 19, 2006 at 01:20:58PM +0100, Vladimir Kisil wrote:
"SA" == Sheplyakov Alexei <varg@theor.jinr.ru> writes: SA> Secondly, drawing is sensible only for small subset of GiNaC SA> classes ... a complex-valued function?....
Yes, complex-valued functions are drawable. Well, such a plot (complex-valued function of a complex variable) would be 4-dimensional. I agree that it is possible to draw it, but IMHO there is no point in doing such things. Thus, I think that plotting functions should not be virtual methods of GiNaC::basic.
SA> I use GiNaC 1.3.5, Asymptote 1.03, g++ 4.1.2
INSTALL recommends Asymptote 1.11
Could you please mention in the INSTALL file that earlier versions are known to *not* work?
Generally, a couple of recent discussions in this list are derived from the more general question:
Is GiNaC a tool for a broad community or it is narrowed to special needs/circumstances?
DISCALIMER: the follwing is simply my personal opinion, see cs.SC/0004015 and hep/ph-0510057 \begin{quote} First of all, GiNaC's name must be read literally. \end{quote} (GiNaC's manual) I think GiNaC is special-purpose library. One of the goals of GiNaC is efficient handling of quite a large expressions (an sum of ~10^6 terms is not really a big expression). Thus, GiNaC provides only basic functionality, since one can't probably do any funky things with such expressions anyway. I don't know if GiNaC's approach is useful for something except calculations in perturbative quantum field theory (and frankly, I don't care much). Best regards, Alexei. -- All science is either physics or stamp collecting.
Dear Alexei,
"ShA" == Sheplyakov Alexei <varg@theor.jinr.ru> writes: ShA> Well, such a plot (complex-valued function of a complex ShA> variable) would be 4-dimensional. I agree that it is possible ShA> to draw it, but IMHO there is no point in doing such ShA> things.
Some people feel differently, see plots of the gamma functions on http://mathworld.wolfram.com/GammaFunction.html ShA> Could you please mention in the INSTALL file that earlier ShA> versions are known to *not* work? This is not a very accurate statement, it is known to work also with v1.10. We did not check the precise margin between "work" and "not work" to make a statement of this sort. ShA> any funky things with such expressions anyway. I don't know if ShA> GiNaC's approach is useful for something except calculations in ShA> perturbative quantum field theory (and frankly, I don't care ShA> much). Thanks for your opinion, this is indeed essential to clarify from the beginning. Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk -- www: http://maths.leeds.ac.uk/~kisilv/
Hello, voicing yet another opinion: Sheplyakov Alexei schrieb:
I think GiNaC is special-purpose library. One of the goals of GiNaC is efficient handling of quite a large expressions (an sum of ~10^6 terms
Yes. Exactly.
is not really a big expression). Thus, GiNaC provides only basic functionality, since one can't probably do any funky things with such expressions anyway. I don't know if GiNaC's approach is useful for
I'd like to see more higher-level functionality in GiNaC :-) (but without sacrificing its initial design principles). High-level functionality is useful sometimes even with huge expressions (such a functionality might be applied not on the whole expression but on its simple building blocks...).
something except calculations in perturbative quantum field theory (and frankly, I don't care much).
The main "feature" of GiNaC is that it is a C++ library! You never guessed that, didn't you ;-) *All* restrictions of its usefulness stem from this fact (and also the lack of manpower available). Suppose we had unlimited manpower for expanding GiNaC. Would its initial design allow for raising its algebra capabilities to levels on par with Mathematica, Maple, etc. Yes! Would people use it then? No! I guess 99% of all people that need to use computer algebra want to find the answers to their mathematical problems by trying/learning/manipulating things *interactively*. GiNaC is not just made for perturbative quantum field theory. But the combination of GiNaC's features and its mode of use are hardly sought after outside this community. Regards, Jens
"JV" == Jens Vollinga <vollinga@physik.uni-wuppertal.de> writes: JV> I guess 99% of all people that need to use computer algebra want JV> to find the answers to their mathematical problems by JV> trying/learning/manipulating things *interactively*.
I cannot see a drastic difference in usage of pyGiNaC and other CAS besides the limitation of currently implemented methods in GiNaC. [But I have to admit I never seriously used any CAS] Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk -- www: http://maths.leeds.ac.uk/~kisilv/
Dear Alexei, On Sat, 19 Aug 2006, Sheplyakov Alexei wrote:
I don't like adding any virtual methods to GiNaC::basic (actually, I'd like to get rid of some already existing ones). Leaving aside "aesthetical" issues (such an approach is completely anti-OO), adding virtual method costs extra bytes (at least, vtable entry should be stored somewhere) for *every* GiNaC object. With real-world expressions this translates into several hundreds of megabytes of RAM wasted for nothing good.
Also leaving the aesthetical issue asside, I really don't believe this story about RAM usage. It would be incredibly inefficient design on the part of the compiler if it were true. I tested this, using a simple test program with a class and allocating a large array of that class. Adding the first virtual function to a class makes the class a bit larger. After that, adding more of them doesn't increase size anymore and also the memory usage of the program doesn't really become much larger. The point is of course that every object of a class does only store a *pointer* to a table of virtual methods and not the table itself. Such a table only needs to be stored only once for every class declared. Best wishes, Chris
On Sat, Aug 19, 2006 at 02:31:30PM +0200, Chris Dams wrote:
The point is of course that every object of a class does only store a *pointer* to a table of virtual methods and not the table itself.
I agree with you, in theory it should be so. But in practice getting rid of [unnecessary] virtual methods *does* help to reduce memory usage. E.g. removing all printing methods (which I use for debugging only, since there is no point in staring throw several-hundreds-megabytes expression, compiling it as a C/C++/whatever code is hopeless too) reduces memory usage by ~10% (and this was extremely important for us due to 3Gb user-space VM limit). Best regards, Alexei. -- All science is either physics or stamp collecting.
Dear Alexei, Sheplyakov Alexei schrieb:
On Sat, Aug 19, 2006 at 02:31:30PM +0200, Chris Dams wrote:
The point is of course that every object of a class does only store a *pointer* to a table of virtual methods and not the table itself.
I agree with you, in theory it should be so. But in practice getting rid of [unnecessary] virtual methods *does* help to reduce memory usage. E.g. removing all printing methods (which I use for debugging only, since there is no point in staring throw several-hundreds-megabytes expression, compiling it as a C/C++/whatever code is hopeless too) reduces memory usage by ~10% (and this was extremely important for us due to 3Gb user-space VM limit).
just out of curiosity: do you have an explanation for that phenomenon? I ask, because your observation - which I don't deny - contradicts my common C++ knowledge. Regards, Jens
participants (7)
-
Chris Dams
-
Daniel Seidel
-
Jens Vollinga
-
Richard B. Kreckel
-
varg@theor.jinr.ru
-
Vladimir Kisil
-
Vladimir V. Kisil