diff --git a/ginac/CMakeLists.txt b/ginac/CMakeLists.txt
index ed6ac11..5803854 100644
--- a/ginac/CMakeLists.txt
+++ b/ginac/CMakeLists.txt
@@ -116,3 +116,2 @@ set(ginaclib_private_headers
     crc32.h
-    hash_seed.h
     compiler.h
diff --git a/ginac/Makefile.am b/ginac/Makefile.am
index 49bd59a..20ba2a8 100644
--- a/ginac/Makefile.am
+++ b/ginac/Makefile.am
@@ -11,3 +11,3 @@ libginac_la_SOURCES = add.cpp archive.cpp basic.cpp clifford.cpp color.cpp \
   utils.cpp wildcard.cpp \
-  remember.h tostring.h utils.h crc32.h hash_seed.h compiler.h \
+  remember.h tostring.h utils.h crc32.h compiler.h \
   parser/parse_binop_rhs.cpp \
diff --git a/ginac/add.cpp b/ginac/add.cpp
index 41f2096..a5c9e67 100644
--- a/ginac/add.cpp
+++ b/ginac/add.cpp
@@ -549,2 +549,5 @@ return_type_t add::return_type_tinfo() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::add)
+
 // Note: do_index_renaming is ignored because it makes no sense for an add.
diff --git a/ginac/add.h b/ginac/add.h
index 4d5bd0a..82d462f 100644
--- a/ginac/add.h
+++ b/ginac/add.h
@@ -69,2 +69,3 @@ protected:
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 	ex thisexpairseq(const epvector & v, const ex & oc, bool do_index_renaming = false) const;
diff --git a/ginac/basic.cpp b/ginac/basic.cpp
index 4287f26..ee41b59 100644
--- a/ginac/basic.cpp
+++ b/ginac/basic.cpp
@@ -35,3 +35,2 @@
 #include "utils.h"
-#include "hash_seed.h"
 #include "inifcns.h"
@@ -783,3 +782,3 @@ unsigned basic::calchash() const
 {
-	unsigned v = make_hash_seed(typeid(*this));
+	unsigned v = gethashseed();
 	for (size_t i=0; i<nops(); i++) {
@@ -798,2 +797,9 @@ unsigned basic::calchash() const
 
+/** Generic hash seed for classes which do not overload this method
+ *  use fast but non-determinsitic hash */
+unsigned basic::gethashseed() const
+{
+	return make_hash_seed_fast(typeid(*this));
+}
+
 /** Function object to be applied by basic::expand(). */
diff --git a/ginac/basic.h b/ginac/basic.h
index 9dc49bf..260f2f8 100644
--- a/ginac/basic.h
+++ b/ginac/basic.h
@@ -227,2 +227,3 @@ protected:
 	virtual unsigned calchash() const;
+	virtual unsigned gethashseed() const;
 	
diff --git a/ginac/clifford.cpp b/ginac/clifford.cpp
index 5b937c4..60cb8ac 100644
--- a/ginac/clifford.cpp
+++ b/ginac/clifford.cpp
@@ -120,2 +120,5 @@ return_type_t clifford::return_type_tinfo() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::clifford)
+
 //////////
@@ -295,2 +298,10 @@ void clifford::do_print_latex(const print_latex & c, unsigned level) const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::diracone)
+DEFAULT_GETHASHSEED(GiNaC::cliffordunit)
+DEFAULT_GETHASHSEED(GiNaC::diracgamma)
+DEFAULT_GETHASHSEED(GiNaC::diracgamma5)
+DEFAULT_GETHASHSEED(GiNaC::diracgammaL)
+DEFAULT_GETHASHSEED(GiNaC::diracgammaR)
+
 DEFAULT_COMPARE(diracone)
diff --git a/ginac/clifford.h b/ginac/clifford.h
index 81e49b0..0f8d087 100644
--- a/ginac/clifford.h
+++ b/ginac/clifford.h
@@ -63,2 +63,3 @@ protected:
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 	// non-virtual functions in this class
@@ -95,2 +96,3 @@ class diracone : public tensor
 protected:
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
@@ -112,2 +114,3 @@ public:
 protected:
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
@@ -128,2 +131,3 @@ public:
 protected:
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
@@ -145,2 +149,3 @@ class diracgamma5 : public tensor
 protected:
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
@@ -162,2 +167,3 @@ class diracgammaL : public tensor
 protected:
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
@@ -179,2 +185,3 @@ class diracgammaR : public tensor
 protected:
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
diff --git a/ginac/color.cpp b/ginac/color.cpp
index 34ab4d8..b181f34 100644
--- a/ginac/color.cpp
+++ b/ginac/color.cpp
@@ -101,2 +101,5 @@ return_type_t color::return_type_tinfo() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::color)
+
 //////////
@@ -150,2 +153,8 @@ bool color::match_same_type(const basic & other) const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::su3one)
+DEFAULT_GETHASHSEED(GiNaC::su3t)
+DEFAULT_GETHASHSEED(GiNaC::su3f)
+DEFAULT_GETHASHSEED(GiNaC::su3d)
+
 DEFAULT_COMPARE(su3one)
diff --git a/ginac/color.h b/ginac/color.h
index cf262a4..d811209 100644
--- a/ginac/color.h
+++ b/ginac/color.h
@@ -61,2 +61,3 @@ protected:
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 
@@ -80,2 +81,3 @@ class su3one : public tensor
 protected:
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
@@ -96,2 +98,3 @@ public:
 protected:
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
@@ -115,2 +118,3 @@ protected:
 	unsigned return_type() const { return return_types::commutative; }
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
@@ -133,2 +137,3 @@ protected:
 	unsigned return_type() const { return return_types::commutative; }
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
diff --git a/ginac/constant.cpp b/ginac/constant.cpp
index b230860..c20f2dd 100644
--- a/ginac/constant.cpp
+++ b/ginac/constant.cpp
@@ -217,7 +217,5 @@ unsigned constant::calchash() const
 {
-	const void* typeid_this = (const void*)typeid(*this).name();
-	hashvalue = golden_ratio_hash((p_int)typeid_this ^ serial);
-
+	unsigned seed = gethashseed();
+	hashvalue = golden_ratio_hash(seed ^ serial);
 	setflag(status_flags::hash_calculated);
-
 	return hashvalue;
@@ -225,2 +223,5 @@ unsigned constant::calchash() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::constant)
+
 //////////
diff --git a/ginac/constant.h b/ginac/constant.h
index 33a7ffc..ca6e3cc 100644
--- a/ginac/constant.h
+++ b/ginac/constant.h
@@ -61,3 +61,4 @@ protected:
 	unsigned calchash() const;
-	
+	unsigned gethashseed() const;
+
 	// non-virtual functions in this class
diff --git a/ginac/container.h b/ginac/container.h
index e2b0a94..d533efd 100644
--- a/ginac/container.h
+++ b/ginac/container.h
@@ -29,2 +29,3 @@
 #include "assertion.h"
+#include "utils.h"
 
@@ -444,2 +445,3 @@ protected:
 	bool is_equal_same_type(const basic & other) const;
+	unsigned gethashseed() const;
 
@@ -638,2 +640,7 @@ bool container<C>::is_equal_same_type(const basic & other) const
 
+/** overload hash seed for deterministic sorting */
+#define HASHSEED_TMPL template <template <class T, class = std::allocator<T> > class C>
+DEFAULT_GETHASHSEED_TMPL(HASHSEED_TMPL, container<C>)
+#undef HASHSEED_TMPL
+
 /** Add element at front. */
diff --git a/ginac/expairseq.cpp b/ginac/expairseq.cpp
index 7dc5582..dba8dea 100644
--- a/ginac/expairseq.cpp
+++ b/ginac/expairseq.cpp
@@ -32,3 +32,2 @@
 #include "utils.h"
-#include "hash_seed.h"
 #include "indexed.h"
@@ -617,3 +616,3 @@ unsigned expairseq::calchash() const
 {
-	unsigned v = make_hash_seed(typeid(*this));
+	unsigned v = gethashseed();
 	epvector::const_iterator i = seq.begin();
@@ -641,2 +640,5 @@ unsigned expairseq::calchash() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::expairseq)
+
 ex expairseq::expand(unsigned options) const
diff --git a/ginac/expairseq.h b/ginac/expairseq.h
index 44d6e26..fcb9d25 100644
--- a/ginac/expairseq.h
+++ b/ginac/expairseq.h
@@ -96,2 +96,3 @@ protected:
 	unsigned calchash() const;
+	unsigned gethashseed() const;
 	ex expand(unsigned options=0) const;
diff --git a/ginac/fail.cpp b/ginac/fail.cpp
index 79581f0..52297e9 100644
--- a/ginac/fail.cpp
+++ b/ginac/fail.cpp
@@ -49,2 +49,5 @@ DEFAULT_CTOR(fail)
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::fail)
+
 DEFAULT_COMPARE(fail)
diff --git a/ginac/fail.h b/ginac/fail.h
index 025d584..e5b773d 100644
--- a/ginac/fail.h
+++ b/ginac/fail.h
@@ -38,2 +38,3 @@ protected:
 	unsigned return_type() const { return return_types::noncommutative_composite; };
+	unsigned gethashseed() const;
 
diff --git a/ginac/fderivative.cpp b/ginac/fderivative.cpp
index bb8dbd4..6047b62 100644
--- a/ginac/fderivative.cpp
+++ b/ginac/fderivative.cpp
@@ -229,2 +229,5 @@ bool fderivative::match_same_type(const basic & other) const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::fderivative)
+
 } // namespace GiNaC
diff --git a/ginac/fderivative.h b/ginac/fderivative.h
index d7a70c2..7cdeb1b 100644
--- a/ginac/fderivative.h
+++ b/ginac/fderivative.h
@@ -73,2 +73,3 @@ protected:
 	bool match_same_type(const basic & other) const;
+	unsigned gethashseed() const;
 
diff --git a/ginac/function.cppy b/ginac/function.cppy
index ce38045..feff726 100644
--- a/ginac/function.cppy
+++ b/ginac/function.cppy
@@ -38,3 +38,2 @@
 #include "utils.h"
-#include "hash_seed.h"
 #include "remember.h"
@@ -468,3 +467,4 @@ unsigned function::calchash() const
 {
-	unsigned v = golden_ratio_hash(make_hash_seed(typeid(*this)) ^ serial);
+	const unsigned seed = gethashseed();
+	unsigned v = golden_ratio_hash(seed ^ serial);
 	for (size_t i=0; i<nops(); i++) {
@@ -481,2 +481,6 @@ unsigned function::calchash() const
 
+
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::function)
+
 ex function::thiscontainer(const exvector & v) const
@@ -873,2 +877 @@ std::string function::get_name() const
 } // namespace GiNaC
-
diff --git a/ginac/function.hppy b/ginac/function.hppy
index 5d7ca09..4590b34 100644
--- a/ginac/function.hppy
+++ b/ginac/function.hppy
@@ -246,2 +246,3 @@ protected:
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 	
diff --git a/ginac/hash_seed.h b/ginac/hash_seed.h
deleted file mode 100644
index 32b057f..0000000
--- a/ginac/hash_seed.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef GINAC_HASH_SEED_H
-#define GINAC_HASH_SEED_H
-/**
- * We need a hash function which gives different values for objects of
- * different types. Hence we need some unique integer for each type.
- * Fortunately, standard C++ RTTI class `type_info' stores a pointer to
- * mangled type name. Normally this pointer is the same for all objects
- * of the same type (although it changes from run to run), so it can be
- * used for computing hashes. However, on some platforms (such as woe32)
- * the pointer returned by type_info::name() might be different even for
- * objects of the same type! Hence we need to resort to comparing string
- * representation of the (mangled) type names. This is quite expensive,
- * so we compare crc32 hashes of those strings. We might got more hash
- * collisions (and slower evaluation as a result), but being a bit slower
- * is much better than being wrong.
- */
-#include <typeinfo>
-#include <cstring>
-#include "crc32.h"
-#include "utils.h"
-#ifdef _WIN32
-#define GINAC_HASH_USE_MANGLED_NAME 1
-#endif
-namespace GiNaC
-{
-#ifndef GINAC_HASH_USE_MANGLED_NAME
-static inline unsigned make_hash_seed(const std::type_info& tinfo)
-{
-	// this pointer is the same for all objects of the same type.
-	// Hence we can use that pointer 
-	const void* mangled_name_ptr = (const void*)tinfo.name();
-	unsigned v = golden_ratio_hash((p_int)mangled_name_ptr);
-	return v;
-}
-#else
-static unsigned make_hash_seed(const std::type_info& tinfo)
-{
-	const char* mangled_name = tinfo.name();
-	return crc32(mangled_name, std::strlen(mangled_name), 0);
-}
-#endif
-} // namespace GiNaC
-#endif /* GINAC_HASH_SEED_H */
-
-
diff --git a/ginac/idx.cpp b/ginac/idx.cpp
index a3f0b84..2c12e99 100644
--- a/ginac/idx.cpp
+++ b/ginac/idx.cpp
@@ -29,3 +29,2 @@
 #include "utils.h"
-#include "hash_seed.h"
 
@@ -317,2 +316,5 @@ bool varidx::match_same_type(const basic & other) const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::varidx)
+
 int spinidx::compare_same_type(const basic & other) const
@@ -343,2 +345,5 @@ bool spinidx::match_same_type(const basic & other) const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::spinidx)
+
 unsigned idx::calchash() const
@@ -353,3 +358,3 @@ unsigned idx::calchash() const
 	// The compare_same_type() methods will take care of the rest.
-	unsigned v = make_hash_seed(typeid(*this));
+	unsigned v = gethashseed();
 	v = rotate_left(v);
@@ -366,2 +371,5 @@ unsigned idx::calchash() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::idx)
+
 /** By default, basic::evalf would evaluate the index value but we don't want
diff --git a/ginac/idx.h b/ginac/idx.h
index a5eda1a..76be6c0 100644
--- a/ginac/idx.h
+++ b/ginac/idx.h
@@ -61,2 +61,3 @@ protected:
 	unsigned calchash() const;
+	unsigned gethashseed() const;
 
@@ -132,2 +133,3 @@ protected:
 	bool match_same_type(const basic & other) const;
+	unsigned gethashseed() const;
 
@@ -184,2 +186,3 @@ protected:
 	bool match_same_type(const basic & other) const;
+	unsigned gethashseed() const;
 
diff --git a/ginac/indexed.cpp b/ginac/indexed.cpp
index b85c386..4501d15 100644
--- a/ginac/indexed.cpp
+++ b/ginac/indexed.cpp
@@ -339,2 +339,5 @@ unsigned indexed::return_type() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::indexed)
+
 ex indexed::expand(unsigned options) const
diff --git a/ginac/indexed.h b/ginac/indexed.h
index 768f7fe..ab34bb9 100644
--- a/ginac/indexed.h
+++ b/ginac/indexed.h
@@ -162,2 +162,3 @@ protected:
 	return_type_t return_type_tinfo() const { return op(0).return_type_tinfo(); }
+	unsigned gethashseed() const;
 	ex expand(unsigned options = 0) const;
diff --git a/ginac/integral.cpp b/ginac/integral.cpp
index 40dd75c..9bda9a2 100644
--- a/ginac/integral.cpp
+++ b/ginac/integral.cpp
@@ -440,2 +440,5 @@ return_type_t integral::return_type_tinfo() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::integral)
+
 ex integral::conjugate() const
diff --git a/ginac/integral.h b/ginac/integral.h
index ac24607..abc408e 100644
--- a/ginac/integral.h
+++ b/ginac/integral.h
@@ -55,2 +55,3 @@ public:
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 	ex conjugate() const;
diff --git a/ginac/matrix.cpp b/ginac/matrix.cpp
index 3e9b28b..2f6327a 100644
--- a/ginac/matrix.cpp
+++ b/ginac/matrix.cpp
@@ -320,2 +320,5 @@ bool matrix::match_same_type(const basic & other) const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::matrix)
+
 /** Automatic symbolic evaluation of an indexed matrix. */
diff --git a/ginac/matrix.h b/ginac/matrix.h
index d45e850..c8e2b66 100644
--- a/ginac/matrix.h
+++ b/ginac/matrix.h
@@ -134,2 +134,3 @@ protected:
 	unsigned return_type() const { return return_types::noncommutative; };
+	unsigned gethashseed() const;
 	
diff --git a/ginac/mul.cpp b/ginac/mul.cpp
index 64660a2..a3cc275 100644
--- a/ginac/mul.cpp
+++ b/ginac/mul.cpp
@@ -991,2 +991,5 @@ return_type_t mul::return_type_tinfo() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::mul)
+
 ex mul::thisexpairseq(const epvector & v, const ex & oc, bool do_index_renaming) const
diff --git a/ginac/mul.h b/ginac/mul.h
index d28b627..da9a5ce 100644
--- a/ginac/mul.h
+++ b/ginac/mul.h
@@ -73,2 +73,3 @@ protected:
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 	ex thisexpairseq(const epvector & v, const ex & oc, bool do_index_renaming = false) const;
diff --git a/ginac/ncmul.cpp b/ginac/ncmul.cpp
index a00a8de..8e20ff0 100644
--- a/ginac/ncmul.cpp
+++ b/ginac/ncmul.cpp
@@ -588,2 +588,5 @@ return_type_t ncmul::return_type_tinfo() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::ncmul)
+
 //////////
diff --git a/ginac/ncmul.h b/ginac/ncmul.h
index 5c56e14..66ee2be 100644
--- a/ginac/ncmul.h
+++ b/ginac/ncmul.h
@@ -75,2 +75,3 @@ protected:
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 	
diff --git a/ginac/power.cpp b/ginac/power.cpp
index 87792b9..8e10b46 100644
--- a/ginac/power.cpp
+++ b/ginac/power.cpp
@@ -788,2 +788,5 @@ return_type_t power::return_type_tinfo() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::power)
+
 ex power::expand(unsigned options) const
diff --git a/ginac/power.h b/ginac/power.h
index fc35791..ed8f2e8 100644
--- a/ginac/power.h
+++ b/ginac/power.h
@@ -82,2 +82,3 @@ protected:
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 	ex expand(unsigned options = 0) const;
diff --git a/ginac/pseries.cpp b/ginac/pseries.cpp
index 4376817..2267a72 100644
--- a/ginac/pseries.cpp
+++ b/ginac/pseries.cpp
@@ -592,2 +592,5 @@ ex pseries::derivative(const symbol & s) const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::pseries)
+
 ex pseries::convert_to_poly(bool no_order) const
diff --git a/ginac/pseries.h b/ginac/pseries.h
index 02ef9b6..c565364 100644
--- a/ginac/pseries.h
+++ b/ginac/pseries.h
@@ -68,2 +68,3 @@ protected:
 	ex derivative(const symbol & s) const;
+	unsigned gethashseed() const;
 
diff --git a/ginac/relational.cpp b/ginac/relational.cpp
index 4ee87be..369e1c5 100644
--- a/ginac/relational.cpp
+++ b/ginac/relational.cpp
@@ -27,3 +27,2 @@
 #include "utils.h"
-#include "hash_seed.h"
 
@@ -262,3 +261,4 @@ unsigned relational::calchash() const
 {
-	unsigned v = make_hash_seed(typeid(*this));
+	unsigned v = gethashseed();
+
 	unsigned lhash = lh.gethash();
@@ -299,2 +299,5 @@ unsigned relational::calchash() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::relational)
+
 //////////
diff --git a/ginac/relational.h b/ginac/relational.h
index 0c0583c..a72a39f 100644
--- a/ginac/relational.h
+++ b/ginac/relational.h
@@ -72,2 +72,3 @@ protected:
 	unsigned calchash() const;
+	unsigned gethashseed() const;
 
diff --git a/ginac/structure.h b/ginac/structure.h
index 867cd42..026075d 100644
--- a/ginac/structure.h
+++ b/ginac/structure.h
@@ -157,2 +157,3 @@ protected:
 	bool match_same_type(const basic & other) const { return true; }
+	unsigned gethashseed() const;
 public:
@@ -242,2 +243,9 @@ int structure<T, CP>::compare_same_type(const basic & other) const
 
+/** overload hash seed for deterministic sorting */
+#define HASHSEED_TMPL template <class T, template <class> class CP>
+#define HASHSEED_CLS structure<T, CP>
+DEFAULT_GETHASHSEED_TMPL(HASHSEED_TMPL, HASHSEED_CLS)
+#undef HASHSEED_TMPL
+#undef HASHSEED_CLS
+
 template <class T, template <class> class CP>
diff --git a/ginac/symbol.cpp b/ginac/symbol.cpp
index 4d73c9e..46115e9 100644
--- a/ginac/symbol.cpp
+++ b/ginac/symbol.cpp
@@ -27,3 +27,2 @@
 #include "utils.h"
-#include "hash_seed.h"
 #include "inifcns.h"
@@ -57,2 +56,5 @@ realsymbol::realsymbol() : symbol() { }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::realsymbol)
+
 // possymbol
@@ -61,2 +63,5 @@ possymbol::possymbol() : realsymbol() { }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::possymbol)
+
 //////////
@@ -274,3 +279,3 @@ unsigned symbol::calchash() const
 {
-	unsigned seed = make_hash_seed(typeid(*this));
+	unsigned seed = gethashseed();
 	hashvalue = golden_ratio_hash(seed ^ serial);
@@ -280,2 +285,5 @@ unsigned symbol::calchash() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::symbol)
+
 //////////
diff --git a/ginac/symbol.h b/ginac/symbol.h
index 519980f..98e812a 100644
--- a/ginac/symbol.h
+++ b/ginac/symbol.h
@@ -67,3 +67,4 @@ protected:
 	unsigned calchash() const;
-	
+	unsigned gethashseed() const;
+
 	// non-virtual functions in this class
@@ -107,2 +108,4 @@ public:
 	realsymbol* duplicate() const { return new realsymbol(*this); }
+protected:
+	unsigned gethashseed() const;
 };
@@ -122,2 +125,4 @@ public:
 	possymbol* duplicate() const { return new possymbol(*this); }
+protected:
+	unsigned gethashseed() const;
 };
diff --git a/ginac/symmetry.cpp b/ginac/symmetry.cpp
index a44cfcc..07ccd98 100644
--- a/ginac/symmetry.cpp
+++ b/ginac/symmetry.cpp
@@ -29,3 +29,2 @@
 #include "utils.h"
-#include "hash_seed.h"
 
@@ -189,3 +188,3 @@ unsigned symmetry::calchash() const
 {
-	unsigned v = make_hash_seed(typeid(*this));
+	unsigned v = gethashseed();
 
@@ -211,2 +210,5 @@ unsigned symmetry::calchash() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::symmetry)
+
 void symmetry::do_print(const print_context & c, unsigned level) const
diff --git a/ginac/symmetry.h b/ginac/symmetry.h
index fa897be..3945947 100644
--- a/ginac/symmetry.h
+++ b/ginac/symmetry.h
@@ -95,2 +95,3 @@ protected:
 	unsigned calchash() const;
+	unsigned gethashseed() const;
 
diff --git a/ginac/tensor.cpp b/ginac/tensor.cpp
index 42056ed..4b69065 100644
--- a/ginac/tensor.cpp
+++ b/ginac/tensor.cpp
@@ -572,2 +572,10 @@ bool tensepsilon::contract_with(exvector::iterator self, exvector::iterator othe
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::tensor)
+DEFAULT_GETHASHSEED(GiNaC::tensdelta)
+DEFAULT_GETHASHSEED(GiNaC::tensmetric)
+DEFAULT_GETHASHSEED(GiNaC::minkmetric)
+DEFAULT_GETHASHSEED(GiNaC::spinmetric)
+DEFAULT_GETHASHSEED(GiNaC::tensepsilon)
+
 //////////
diff --git a/ginac/tensor.h b/ginac/tensor.h
index fb8185b..e4a3f5a 100644
--- a/ginac/tensor.h
+++ b/ginac/tensor.h
@@ -40,2 +40,3 @@ protected:
 	unsigned return_type() const { return return_types::noncommutative_composite; }
+	unsigned gethashseed() const;
 
@@ -65,2 +66,3 @@ protected:
 	unsigned return_type() const { return return_types::commutative; }
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
@@ -87,2 +89,3 @@ protected:
 	unsigned return_type() const { return return_types::commutative; }
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
@@ -116,2 +119,3 @@ protected:
 	unsigned return_type() const { return return_types::commutative; }
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
@@ -141,2 +145,3 @@ public:
 protected:
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
@@ -171,2 +176,3 @@ protected:
 	unsigned return_type() const { return return_types::commutative; }
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
diff --git a/ginac/utils.h b/ginac/utils.h
index 102f09d..acdf9d1 100644
--- a/ginac/utils.h
+++ b/ginac/utils.h
@@ -77,4 +77,16 @@ typedef unsigned long p_int;
 
+/** 32 bit FNV-1a hash of a string. */
+static inline unsigned string_fnv_hash(const char* str)
+{
+	const unsigned char* s = reinterpret_cast<const unsigned char*>(str);
+	unsigned hash = 2166136261;
+	while (*s) {
+		hash ^= static_cast<unsigned>(*s++);
+		hash *= 16777619;
+	}
+	return hash;
+}
+
 /** Truncated multiplication with golden ratio, for computing hash values. */
-inline unsigned golden_ratio_hash(p_int n)
+static inline unsigned golden_ratio_hash(p_int n)
 {
@@ -104,2 +116,33 @@ inline unsigned golden_ratio_hash(p_int n)
 
+static inline unsigned make_hash_seed(const char* string)
+{
+	const unsigned seed = string_fnv_hash(string);
+	return seed;
+}
+static inline unsigned make_hash_seed(const std::type_info& tinfo)
+{
+	// type name is the same for all objects of the same type
+	return make_hash_seed(tinfo.name());
+}
+
+#ifdef _WIN32
+#define GINAC_HASH_USE_MANGLED_NAME 1
+#endif
+#ifndef GINAC_HASH_USE_MANGLED_NAME
+static inline unsigned make_hash_seed_fast(const std::type_info& tinfo)
+{
+	// this pointer is the same for all objects of the same type.
+	// Hence we can use that pointer
+	const void* mangled_name_ptr = (const void*)tinfo.name();
+	unsigned v = golden_ratio_hash((p_int)mangled_name_ptr);
+	return v;
+}
+#else
+static inline unsigned make_hash_seed_fast(const std::type_info& tinfo)
+{
+	// fast version doesn't work on windows
+	return make_hash_seed(tinfo);
+}
+#endif
+
 /* Compute the sign of a permutation of a container, with and without an
@@ -427,2 +470,27 @@ int classname::compare_same_type(const basic & other) const \
 
+#define DEFAULT_GETHASHSEED_TMPL(tmplprefix, classname) \
+tmplprefix \
+unsigned classname::gethashseed() const \
+{ \
+	const std::type_info& this_type = typeid(*this); \
+	if (this_type == typeid(classname)) { \
+		static const unsigned seed = make_hash_seed(this_type); \
+		return seed; \
+	} else { \
+		return make_hash_seed_fast(this_type); \
+	} \
+}
+
+#define DEFAULT_GETHASHSEED(classname) \
+unsigned classname::gethashseed() const \
+{ \
+	const std::type_info& this_type = typeid(*this); \
+	if (this_type == typeid(classname)) { \
+		static const unsigned seed = make_hash_seed("" #classname); \
+		return seed; \
+	} else { \
+		return make_hash_seed_fast(this_type); \
+	} \
+}
+
 #define DEFAULT_PRINT(classname, text) \
diff --git a/ginac/wildcard.cpp b/ginac/wildcard.cpp
index 6140fa5..5a507a2 100644
--- a/ginac/wildcard.cpp
+++ b/ginac/wildcard.cpp
@@ -25,3 +25,2 @@
 #include "utils.h"
-#include "hash_seed.h"
 
@@ -109,3 +108,3 @@ unsigned wildcard::calchash() const
 	// is not good enough yet...
-	unsigned seed = make_hash_seed(typeid(*this));
+	const unsigned seed = gethashseed();
 	hashvalue = golden_ratio_hash(seed ^ label);
@@ -115,2 +114,5 @@ unsigned wildcard::calchash() const
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(GiNaC::wildcard)
+
 bool wildcard::match(const ex & pattern, exmap& repl_lst) const
diff --git a/ginac/wildcard.h b/ginac/wildcard.h
index 678afb8..1612592 100644
--- a/ginac/wildcard.h
+++ b/ginac/wildcard.h
@@ -51,2 +51,3 @@ protected:
 	unsigned calchash() const;
+	unsigned gethashseed() const;
 
