<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><p style="font:14px/1.5 Lucida Grande;margin:0;">Thanks very much for the patch!</p><p style="font:14px/1.5 Lucida Grande;margin:0;"><br></p><p style="font:14px/1.5 Lucida Grande;margin:0;">And again thanks a lot for the suggestions for Symbol::<span style="white-space: pre-wrap;">calchash,</span></p><p style="font-stretch: normal; line-height: 1.5; margin: 0px;"><span style="white-space: pre-wrap;">that is really what I am looking for!</span></p><p style="font:14px/1.5 Lucida Grande;margin:0;"><span style="white-space: pre-wrap;"><br></span></p><p style="font:14px/1.5 Lucida Grande;margin:0;"><span style="white-space: pre-wrap;">Best regards!</span></p><p style="font:14px/1.5 Lucida Grande;margin:0;"><span style="white-space: pre-wrap;">Feng</span></p><span style="font: 14px/1.5 'Lucida Grande';color:#333;"><br></span><div class="foxmail_blockquote_fromhere_element" style="font: 12px/1.5 'Lucida Grande';padding:2px 0 2px 0;">                            </div><div style="border-left: solid 3px #EAEAEA; padding-left: 10px"><div style="font: 12px/1.5 'PingFangSC-Regular';color:#70727B;">在 2021年12月20日 16:57,Oleg Finkelshteyn<olegfink@gmail.com> 写道:</div><br><div class="mail_quote_BB21DFF4DCBC409186E7B3EC17B6909F" style="font: 14px/1.5 'Lucida Grande';color:#333;"><pre style="white-space:pre-wrap;">i suspect this is actually due to a typo in relational::compare_same_type.

(basic reality check: pathologic (e.g. constant) hash functions should lead to degraded performance, not different results)

diff --git a/ginac/relational.cpp b/ginac/relational.cpp
index 599a2635..dbc541a3 100644
--- a/ginac/relational.cpp
+++ b/ginac/relational.cpp
@@ -223,8 +223,8 @@ int relational::compare_same_type(const basic & other) const
                                return (o < oth.o) ? -1 : 1;
                        break;
        }
-       const int lcmpval = lh.compare(oth.rh);
-       return (lcmpval!=0) ? lcmpval : rh.compare(oth.lh);
+       const int lcmpval = lh.compare(oth.lh);
+       return (lcmpval!=0) ? lcmpval : rh.compare(oth.rh);
}
 
attached is also a shorter test along the same lines as Feng's. 
it prints the result of comparing two symbol==0 expressions to each other both ways.
without the patch, the output is -1 -1 (which is inconsistent), and with the patch it's -1 1.

a hash collision is needed to elicit this bug because basic::compare returns early without calling compare_same_type if hashes differ.

Feng: regardless of this bug, i think you'll want something like following:

unsigned Symbol::calchash() const {
      hashvalue = get_symbol(get_name()).gethash();
      setflag(status_flags::hash_calculated);
      return hashvalue;
}

thanks

On Sat, 18 Dec 2021, at 11:10, Vladimir V. Kisil wrote:
>>>>>> On Sat, 18 Dec 2021 16:22:22 +0800, Feng Feng <<a href="mailto:f.feng@outlook.com" title="mailto:f.feng@outlook.com">f.feng@outlook.com</a>> said:
>     FF> I got a strange behaviour while implementing the archive in
>     FF> user-defined class, to make the behaviour more explicitly, let
>
>     If you will delete the method Symbol::calchash() from your class you
>   will get the expected behaviour.
> -- 
> Vladimir V. Kisil                 <a href="http://www.maths.leeds.ac.uk/~kisilv/" title="http://www.maths.leeds.ac.uk/~kisilv/">http://www.maths.leeds.ac.uk/~kisilv/</a>
>   Book:      Geometry of Mobius Maps       <a href="https://doi.org/10.1142/p835" title="https://doi.org/10.1142/p835">https://doi.org/10.1142/p835</a>
>   Soft:      Geometry of cycles         <a href="http://moebinv.sourceforge.net/" title="http://moebinv.sourceforge.net/">http://moebinv.sourceforge.net/</a>
>   Jupyter notebooks:        <a href="https://github.com/vvkisil?tab=repositories" title="https://github.com/vvkisil?tab=repositories">https://github.com/vvkisil?tab=repositories</a>
>>>>>> On Sat, 18 Dec 2021 16:22:22 +0800, Feng Feng <<a href="mailto:f.feng@outlook.com" title="mailto:f.feng@outlook.com">f.feng@outlook.com</a>> said:
>
>     FF> Dear all,
>
>
>     FF> I got a strange behaviour while implementing the archive in
>     FF> user-defined class, to make the behaviour more explicitly, let
>     FF> me post the C++ code here:
>
>
>     FF> #include <ginac/ginac.h> #include <fstream>
>
>
>     FF> using namespace GiNaC; using namespace std;
>
>
>     FF> class Symbol : public symbol {
>     FF> GINAC_DECLARE_REGISTERED_CLASS(Symbol, symbol) public:
>     FF> Symbol(const string &s); void archive(archive_node & n) const
>     FF> override; void read_archive(const archive_node& n, lst& sym_lst)
>     FF> override; unsigned calchash() const override; };
>     FF> GINAC_DECLARE_UNARCHIVER(Symbol);
>
>
>     FF> GINAC_IMPLEMENT_REGISTERED_CLASS(Symbol, symbol)
>     FF> GINAC_BIND_UNARCHIVER(Symbol);
>
>
>     FF> const symbol & get_symbol(const string & s) { static map<string,
>     FF> symbol> dict; if (dict.find(s) == dict.end()) dict[s] =
>     FF> symbol(s); return dict[s]; }
>
>
>     FF> Symbol::Symbol() { } Symbol::Symbol(const string &s) :
>     FF> symbol(get_symbol(s)) { } int Symbol::compare_same_type(const
>     FF> basic &other) const { const Symbol &o = static_cast<const Symbol
>     FF> &>(other); int ret = get_name().compare(o.get_name());
>     FF> if(ret==0) return 0; else if(ret<0) return -1; else return 1; }

>     FF> void Symbol::archive(archive_node & n) const {
>     FF> inherited::archive(n); }
>    
>     FF> void Symbol::read_archive(const archive_node& n, lst& sym_lst) {
>     FF> inherited::read_archive(n, sym_lst); *this = Symbol(get_name());
>     FF> }
>
>
>     FF> unsigned Symbol::calchash() const { static auto hash =
>     FF> symbol("_").gethash(); return hash; }
>
>
>     FF> int main() { Symbol k1("k1"), k2("k2"); auto garfn = "tmp.gar";
>    
>     FF>     { archive ar; ex val = lst{ k1*k1, k2*k2 };
>     FF> ar.archive_ex(val, "key"); ofstream out(garfn); out << ar;
>     FF> out.close(); cout << "writed: " << val << endl; } { archive ar;
>     FF> ifstream in(garfn); in >> ar; in.close(); auto val =
>     FF> ar.unarchive_ex(lst{}, "key"); cout << "read: " << val << endl;
>     FF> } // console output is // writed: {k1^2,k2^2} // read:
>     FF> {k1^2,k2^2}
>    
>     FF>     { archive ar; ex val = lst{ k1*k1==0, k2*k2==0 };
>     FF> ar.archive_ex(val, "key"); ofstream out(garfn); out << ar;
>     FF> out.close(); cout << "writed: " << val << endl; } { archive ar;
>     FF> ifstream in(garfn); in >> ar; in.close(); auto val =
>     FF> ar.unarchive_ex(lst{}, "key"); cout << "read: " << val << endl;
>     FF> } // console output is // writed: {k1^2==0,k2^2==0} // read:
>     FF> {k1^2==0,k1^2==0} // Note that the last line above, both items
>     FF> are the same: k1^2==0
>    
>     FF>     return 0; }
>
>
>     FF> Here I want to introduce a class Symbol, when one defines Symbol
>     FF> a(“a”), b(“a”);, then a and b will be the same or equal, so I
>     FF> override the method compare_same_type.
>
>
>
>
>     FF> The last console output seems very strange to me, the both items
>     FF> are the same, while the expected result is "read:
>     FF> {k1^2==0,k2^2==0}”.
>
>
>     FF> Thanks very much!
>
>
>     FF> Best regards!  Feng
>
>     FF> ----------------------------------------------------
>     FF> Alternatives:
>
>     FF> ----------------------------------------------------
>     FF> _______________________________________________ GiNaC-list
>     FF> mailing list <a href="mailto:GiNaC-list@ginac.de" title="mailto:GiNaC-list@ginac.de">GiNaC-list@ginac.de</a>
>     FF> <a href="https://www.ginac.de/mailman/listinfo/ginac-list" title="https://www.ginac.de/mailman/listinfo/ginac-list">https://www.ginac.de/mailman/listinfo/ginac-list</a>
> _______________________________________________
> GiNaC-list mailing list
> <a href="mailto:GiNaC-list@ginac.de" title="mailto:GiNaC-list@ginac.de">GiNaC-list@ginac.de</a>
> <a href="https://www.ginac.de/mailman/listinfo/ginac-list" title="https://www.ginac.de/mailman/listinfo/ginac-list">https://www.ginac.de/mailman/listinfo/ginac-list</a>
</pre></div></div>