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