Hi, I'm a mathematician and I find GiNaC very useful for doing calculations. Unfortunately, the new tinfo mechanism in version 1.4.0 breaks my code, and I am not sure how to fix that. Basically, what I need is an efficient version of is_a (actually, is_a<ncmul>) that does not rely on dynamic_cast. With the old tinfo method, I could simply redefine: template<> inline bool is_a<ncmul>(const basic & obj) { return (obj.tinfo()&TINFO_MASK)==TINFO_ncmul; } where TINFO_MASK is the constant 0x001fffffU, and the classes I derived from ncmul had appropriate tinfo constants. With the new method, where the tinfo_key is a pointer, the above code does not work. One obvious alternative is the following: struct tinfo_static_t <http://www.ginac.de/reference/structGiNaC_1_1tinfo__static__t.html> { const tinfo_static_t* derives_from; //NULL if derived from void, otherwise points to tinfo_static member in superclass <http://www.ginac.de/reference/structGiNaC_1_1tinfo__static__t.html> }; typedef const tinfo_static_t * tinfo_t; and then template <class T> inline bool is_a(const basic &obj) { const tinfo_static_t* tinfo=obj.tinfo(); do { if (tinfo==&T::tinfo_static) return true; tinfo = tinfo->derives_from <http://www.ginac.de/reference/structGiNaC_1_1tinfo__static__t.html>; } while (tinfo!=NULL); return false; } This appears reasonably efficient, but it will not work because, for instance, add::return_type_tinfo <http://www.ginac.de/reference/classGiNaC_1_1add.html#b2>() can return this, which can be converted to a pointer to void but not to a pointer to tinfo_static_t. I really do not understand the meaning of this choice. Can someone explain? What would I need to change in order to make the above code work? Thanks in advance Diego Conti
Hello! First of all, it would be nice to see the actual code which proves $subject. On Mon, Sep 10, 2007 at 04:26:49PM +0200, Diego Conti wrote:
Unfortunately, the new tinfo mechanism in version 1.4.0 breaks my code, and I am not sure how to fix that. Basically, what I need is an efficient version of is_a (actually, is_a<ncmul>) that does not rely on dynamic_cast.
With the old tinfo method, I could simply redefine:
template<> inline bool is_a<ncmul>(const basic & obj) { return (obj.tinfo()&TINFO_MASK)==TINFO_ncmul; }
I think such a redifinition might break some GiNaC classes...
where TINFO_MASK is the constant 0x001fffffU, and the classes I derived from ncmul had appropriate tinfo constants.
... but anyway, is it really faster?
With the new method, where the tinfo_key is a pointer, the above code does not work. One obvious alternative is the following:
struct tinfo_static_t <http://www.ginac.de/reference/structGiNaC_1_1tinfo__static__t.html> { const tinfo_static_t* derives_from; //NULL if derived from void, otherwise points to tinfo_static member in superclass <http://www.ginac.de/reference/structGiNaC_1_1tinfo__static__t.html> };
Ugh, now every object (even a symbol) carries information about relationship between _all_ GiNaC classes. Not so nice.
typedef const tinfo_static_t * tinfo_t;
and then
template <class T> inline bool is_a(const basic &obj) { const tinfo_static_t* tinfo=obj.tinfo(); do { if (tinfo==&T::tinfo_static) return true; tinfo = tinfo->derives_from <http://www.ginac.de/reference/structGiNaC_1_1tinfo__static__t.html>; } while (tinfo!=NULL); return false; }
This appears reasonably efficient,
Yes, but I doubt it will be any better than dynamic_cast. It uses very similar technique (see e.g. <cxxabi.h> from GNU libstdc++). Best regards, Alexei. -- All science is either physics or stamp collecting.
Thanks for your reply. I have made some tests, and I think I may have found a more serious (possibly unrelated) problem, i.e. version 1.4.0 appears to be 10 times slower than 1.3.8! Or am I missing something? Here is my test program: #include <ginac/ginac.h> #include <ginac/version.h> #include <iostream> #include <time.h> using namespace GiNaC; using namespace std; const unsigned TINFO_DifferentialOneForm =0x00200000U; class DifferentialOneForm : public basic { GINAC_DECLARE_REGISTERED_CLASS(DifferentialOneForm,basic); int id; public: DifferentialOneForm(int ID) {id=ID;} unsigned return_type() const {return return_types::noncommutative;} tinfo_t return_type_tinfo() const {return &tinfo_static;} //1.4.0 //unsigned return_type_tinfo() const {return TINFO_DifferentialOneForm;} //1.3.8 void do_print(const print_context & c, unsigned level) const { c.s<<"Alpha_"<<id; } }; GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(DifferentialOneForm,basic,print_func<print_context>(&DifferentialOneForm::do_print)); void DifferentialOneForm::archive(archive_node & n) const {} DifferentialOneForm::DifferentialOneForm(const archive_node & n, lst & sym_lst) {}; ex DifferentialOneForm::unarchive(const archive_node & n, lst & sym_lst) {return 0;} int DifferentialOneForm::compare_same_type(const basic & other) const { const DifferentialOneForm& o=static_cast<const DifferentialOneForm&>(other); if (id<o.id) return -1; else if (id>o.id) return 1; else return 0; } DifferentialOneForm::DifferentialOneForm() {id=0;} int main() { DifferentialOneForm u(1),v(2),w(3),s(4),t(5),r(6); symbol x,y,p; ex a=x*u*v+y*w*s+p*t*r; cout<<"Ginac "<<version_major<<"."<<version_minor<<"."<<version_micro<<endl; clock_t start_clock=clock(); for (int i=0;i<100000;i++) a*a*a; cout<<"Product test: time elapsed: "<<(1000* (clock()-start_clock))/CLOCKS_PER_SEC <<"ms"<<endl; } Output: Ginac 1.4.0 Product test: time elapsed: 4770ms Ginac 1.3.8 Product test: time elapsed: 480ms
Hello!
First of all, it would be nice to see the actual code which proves $subject.
Well, I didn't mean it literally, only that my hack that is supposed to speed up is_a does not work any longer. But you are probably right that said hack did not make much of a difference.
With the old tinfo method, I could simply redefine:
template<> inline bool is_a<ncmul>(const basic & obj) { return (obj.tinfo()&TINFO_MASK)==TINFO_ncmul; }
I think such a redifinition might break some GiNaC classes...
But aren't all the tinfo's defined in the file tinfos.h? Then they all satisfy tinfo | TINFO_MASK = TINFO_MASK meaning that the remaning bits are safe to use.
where TINFO_MASK is the constant 0x001fffffU, and the classes I derived from ncmul had appropriate tinfo constants.
... but anyway, is it really faster?
Maybe only slightly so. Is there anything faster than a bitwise AND anyway? I don't really understand how dynamic_cast works, but I thought there was some overhead in the case of multiple inheritance...
With the new method, where the tinfo_key is a pointer, the above code does not work. One obvious alternative is the following:
struct tinfo_static_t <http://www.ginac.de/reference/structGiNaC_1_1tinfo__static__t.html> { const tinfo_static_t* derives_from; //NULL if derived from void, otherwise points to tinfo_static member in superclass <http://www.ginac.de/reference/structGiNaC_1_1tinfo__static__t.html> };
Ugh, now every object (even a symbol) carries information about relationship between _all_ GiNaC classes. Not so nice.
Well, no...if I understand correctly, each GiNaC class has a member of type tinfo_static_t, but it's a static member. So, every class (not every object) carries that information, which seems alright to me.
typedef const tinfo_static_t * tinfo_t;
and then
template <class T> inline bool is_a(const basic &obj) { const tinfo_static_t* tinfo=obj.tinfo(); do { if (tinfo==&T::tinfo_static) return true; tinfo = tinfo->derives_from <http://www.ginac.de/reference/structGiNaC_1_1tinfo__static__t.html>; } while (tinfo!=NULL); return false; }
This appears reasonably efficient,
Yes, but I doubt it will be any better than dynamic_cast. It uses very similar technique (see e.g. <cxxabi.h> from GNU libstdc++).
Oh, I see. Best, Diego
On Tue, Sep 11, 2007 at 05:07:58PM +0200, Diego Conti wrote:
I have made some tests, and I think I may have found a more serious (possibly unrelated) problem, i.e. version 1.4.0 appears to be 10 times slower than 1.3.8!
I've reproduced this. Unfortunately, I have no idea what is the reason of the slowdown. $ cat reg.cpp #include <ginac/ginac.h> #include <ginac/version.h> #include <iostream> using namespace GiNaC; #if GINACLIB_MINOR_VERSION == 3 const unsigned TINFO_DifferentialOneForm =0x00200000U; #endif class DifferentialOneForm : public basic { GINAC_DECLARE_REGISTERED_CLASS(DifferentialOneForm,basic); const int id; public: DifferentialOneForm(const int ID) : id(ID) { } unsigned return_type() const {return return_types::noncommutative;} #if GINACLIB_MINOR_VERSION <= 3 unsigned return_type_tinfo() const {return TINFO_DifferentialOneForm;} #else tinfo_t return_type_tinfo() const {return &tinfo_static; } #endif void do_print(const print_context & c, unsigned level) const { c.s<<"Alpha_"<<id; } }; GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(DifferentialOneForm, basic, print_func<print_context>(&DifferentialOneForm::do_print)) void DifferentialOneForm::archive(archive_node & n) const { } DifferentialOneForm::DifferentialOneForm(const archive_node & n, lst & sym_lst) : id(0) { } ex DifferentialOneForm::unarchive(const archive_node & n, lst & sym_lst) { return 0; } int DifferentialOneForm::compare_same_type(const basic & other) const { const DifferentialOneForm& o=static_cast<const DifferentialOneForm&>(other); if (id<o.id) return -1; else if (id>o.id) return 1; else return 0; } DifferentialOneForm::DifferentialOneForm() : id(0) { } int main(int argc, char** argv) { DifferentialOneForm u(1),v(2),w(3),s(4),t(5),r(6); symbol x,y,p; ex a=x*u*v+y*w*s+p*t*r; const size_t ntests=10000; for (size_t i=0; i<ntests; i++) a*a*a; std::cout << a << std::endl; return 0; } $ g++ -I ginac-1.4 -o reg.1.4 reg.cpp -L./ginac-1.4/lib -lginac -Wl,--rpath=`pwd`/ginac-1.4/lib $ g++ -I ginac-1.3 -o reg reg.cpp -L./ginac-1.3/lib -lginac -Wl,--rpath=`pwd`/ginac-1.3/lib $ ldd ./reg | grep ginac | cut -d ' ' -f 1 libginac-1.3.so.2 $ ldd ./reg.1.4 | grep ginac | cut -d ' ' -f 1 libginac-1.4.so.0 $ time ./reg >/dev/null 2>&1 real 0m0.064s user 0m0.064s sys 0m0.000s $ time ./reg.1.4 >/dev/null 2>&1 real 0m0.690s user 0m0.680s sys 0m0.012s I've made some interesting observations. 1. The "old" (1.3.8) version gives stable result (i.e. it does not change from run to run): $ for i in `seq 1 50`; do ./reg; done | sort -n | uniq symbol3*(Alpha_5*Alpha_6)+symbol1*(Alpha_1*Alpha_2)+symbol2*(Alpha_3*Alpha_4) With new one (1.4.0) result is not stable any more: $ for i in `seq 1 50`; do ./reg.1.4 ; done | sort -n | uniq (Alpha_1*Alpha_2)*symbol1+(Alpha_3*Alpha_4)*symbol2+(Alpha_5*Alpha_6)*symbol3 (Alpha_1*Alpha_2)*symbol1+(Alpha_3*Alpha_4)*symbol2+symbol3*(Alpha_5*Alpha_6) (Alpha_1*Alpha_2)*symbol1+(Alpha_5*Alpha_6)*symbol3+symbol2*(Alpha_3*Alpha_4) (Alpha_1*Alpha_2)*symbol1+symbol2*(Alpha_3*Alpha_4)+(Alpha_5*Alpha_6)*symbol3 (Alpha_3*Alpha_4)*symbol2+(Alpha_1*Alpha_2)*symbol1+(Alpha_5*Alpha_6)*symbol3 (Alpha_3*Alpha_4)*symbol2+(Alpha_1*Alpha_2)*symbol1+symbol3*(Alpha_5*Alpha_6) (Alpha_3*Alpha_4)*symbol2+(Alpha_5*Alpha_6)*symbol3+(Alpha_1*Alpha_2)*symbol1 (Alpha_5*Alpha_6)*symbol3+(Alpha_1*Alpha_2)*symbol1+(Alpha_3*Alpha_4)*symbol2 (Alpha_5*Alpha_6)*symbol3+(Alpha_3*Alpha_4)*symbol2+(Alpha_1*Alpha_2)*symbol1 (Alpha_5*Alpha_6)*symbol3+symbol1*(Alpha_1*Alpha_2)+(Alpha_3*Alpha_4)*symbol2 (Alpha_5*Alpha_6)*symbol3+symbol1*(Alpha_1*Alpha_2)+symbol2*(Alpha_3*Alpha_4) (Alpha_5*Alpha_6)*symbol3+symbol2*(Alpha_3*Alpha_4)+(Alpha_1*Alpha_2)*symbol1 symbol1*(Alpha_1*Alpha_2)+(Alpha_5*Alpha_6)*symbol3+symbol2*(Alpha_3*Alpha_4) symbol1*(Alpha_1*Alpha_2)+symbol2*(Alpha_3*Alpha_4)+(Alpha_5*Alpha_6)*symbol3 symbol1*(Alpha_1*Alpha_2)+symbol2*(Alpha_3*Alpha_4)+symbol3*(Alpha_5*Alpha_6) symbol1*(Alpha_1*Alpha_2)+symbol3*(Alpha_5*Alpha_6)+symbol2*(Alpha_3*Alpha_4) symbol2*(Alpha_3*Alpha_4)+(Alpha_5*Alpha_6)*symbol3+symbol1*(Alpha_1*Alpha_2) symbol2*(Alpha_3*Alpha_4)+symbol1*(Alpha_1*Alpha_2)+(Alpha_5*Alpha_6)*symbol3 symbol3*(Alpha_5*Alpha_6)+(Alpha_1*Alpha_2)*symbol1+(Alpha_3*Alpha_4)*symbol2 symbol3*(Alpha_5*Alpha_6)+(Alpha_3*Alpha_4)*symbol2+symbol1*(Alpha_1*Alpha_2) symbol3*(Alpha_5*Alpha_6)+symbol1*(Alpha_1*Alpha_2)+symbol2*(Alpha_3*Alpha_4) symbol3*(Alpha_5*Alpha_6)+symbol2*(Alpha_3*Alpha_4)+symbol1*(Alpha_1*Alpha_2) 2. This regression has something to do with handling non-commutative expressions (e.g. there is no such slowdown with polynomials or rational functions). Best regards, Alexei -- All science is either physics or stamp collecting.
Hi, Sheplyakov Alexei schrieb:
I've reproduced this. Unfortunately, I have no idea what is the reason of the slowdown.
it's one of Chris' patches for dummy indices renaming that introduced that slowdown. At the moment I am not sure which one. Regards, Jens
Hello! On Wed, Sep 12, 2007 at 03:14:02PM +0200, Jens Vollinga wrote:
it's one of Chris' patches for dummy indices renaming that introduced that slowdown.
I don't quite understand. The expression in question has no indices at all.
At the moment I am not sure which one.
This one: commit 9507ddbf35326a15e98428f81b095d300b1a84cc Author: Chris Dams <Chris.Dams@mi.infn.it> Date: Mon Aug 21 14:59:11 2006 +0000 Reverting it removes the slowdown. Best regards, Alexei -- All science is either physics or stamp collecting.
Hi, Sheplyakov Alexei schrieb:
Hello!
On Wed, Sep 12, 2007 at 03:14:02PM +0200, Jens Vollinga wrote:
it's one of Chris' patches for dummy indices renaming that introduced that slowdown.
I don't quite understand. The expression in question has no indices at all.
Chris' patch from 21 Aug 2006 that is labeled "Made also ncmuls rename dummy indices." introduces the slowdown.
At the moment I am not sure which one.
This one:
commit 9507ddbf35326a15e98428f81b095d300b1a84cc Author: Chris Dams <Chris.Dams@mi.infn.it> Date: Mon Aug 21 14:59:11 2006 +0000
Reverting it removes the slowdown.
Best regards, Alexei
Now I am confused! What should that text tell me? It is no CVS log. Is it an excerpt from a private conversation? A private git commit?!? Regards, Jens
Hi, On Wed, Sep 12, 2007 at 05:24:42PM +0200, Jens Vollinga wrote:
Chris' patch from 21 Aug 2006 that is labeled "Made also ncmuls rename dummy indices." introduces the slowdown.
Well, I was aware of that -- I played with Diegos code, did git-bisect and found out "bad" patch. However, I don't understand _why_ that patch slows down the evaluation of the expression which has no indices at all.
commit 9507ddbf35326a15e98428f81b095d300b1a84cc Author: Chris Dams <Chris.Dams@mi.infn.it> Date: Mon Aug 21 14:59:11 2006 +0000
Reverting it removes the slowdown.
Now I am confused! What should that text tell me? It is no CVS log. Is it an excerpt from a private conversation? A private git commit?!?
This is git commit. It is not exactly private, the repository is available at http://theor.jinr.ru/~varg/git/ginac It contains "official" and "hijacked" branches. "Official" ones are mirrored from GiNaC CVS. I thought the date would help you to identify corresponding CVS commit[s]. Best regards, Alexei -- All science is either physics or stamp collecting.
participants (3)
-
Diego Conti
-
Jens Vollinga
-
varg@theor.jinr.ru