diff --git a/ginac/CMakeLists.txt b/ginac/CMakeLists.txt
index ed6ac11..5803854 100644
--- a/ginac/CMakeLists.txt
+++ b/ginac/CMakeLists.txt
@@ -115,5 +115,4 @@ set(ginaclib_private_headers
     utils.h
     crc32.h
-    hash_seed.h
     compiler.h
     parser/lexer.h
diff --git a/ginac/Makefile.am b/ginac/Makefile.am
index 49bd59a..20ba2a8 100644
--- a/ginac/Makefile.am
+++ b/ginac/Makefile.am
@@ -10,5 +10,5 @@ libginac_la_SOURCES = add.cpp archive.cpp basic.cpp clifford.cpp color.cpp \
   pseries.cpp print.cpp symbol.cpp symmetry.cpp tensor.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 \
   parser/parser.cpp \
diff --git a/ginac/add.cpp b/ginac/add.cpp
index 41f2096..09e6263 100644
--- a/ginac/add.cpp
+++ b/ginac/add.cpp
@@ -548,4 +548,7 @@ return_type_t add::return_type_tinfo() const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(add)
+
 // Note: do_index_renaming is ignored because it makes no sense for an add.
 ex add::thisexpairseq(const epvector & v, const ex & oc, bool do_index_renaming) const
diff --git a/ginac/add.h b/ginac/add.h
index 4d5bd0a..82d462f 100644
--- a/ginac/add.h
+++ b/ginac/add.h
@@ -68,4 +68,5 @@ protected:
 	unsigned return_type() const;
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 	ex thisexpairseq(const epvector & v, const ex & oc, bool do_index_renaming = false) const;
 	ex thisexpairseq(std::auto_ptr<epvector> vp, 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
@@ -34,5 +34,4 @@
 #include "archive.h"
 #include "utils.h"
-#include "hash_seed.h"
 #include "inifcns.h"
 
@@ -782,5 +781,5 @@ return_type_t basic::return_type_tinfo() const
 unsigned basic::calchash() const
 {
-	unsigned v = make_hash_seed(typeid(*this));
+	unsigned v = gethashseed();
 	for (size_t i=0; i<nops(); i++) {
 		v = rotate_left(v);
@@ -797,4 +796,11 @@ 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(). */
 struct expand_map_function : public map_function {
diff --git a/ginac/basic.h b/ginac/basic.h
index 9dc49bf..260f2f8 100644
--- a/ginac/basic.h
+++ b/ginac/basic.h
@@ -226,4 +226,5 @@ protected:
 
 	virtual unsigned calchash() const;
+	virtual unsigned gethashseed() const;
 	
 	// non-virtual functions in this class
diff --git a/ginac/clifford.cpp b/ginac/clifford.cpp
index 5b937c4..4010218 100644
--- a/ginac/clifford.cpp
+++ b/ginac/clifford.cpp
@@ -119,4 +119,7 @@ return_type_t clifford::return_type_tinfo() const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(clifford)
+
 //////////
 // archiving
diff --git a/ginac/clifford.h b/ginac/clifford.h
index 81e49b0..750288c 100644
--- a/ginac/clifford.h
+++ b/ginac/clifford.h
@@ -62,4 +62,5 @@ protected:
 	unsigned return_type() const { return return_types::noncommutative; }
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 	// non-virtual functions in this class
 public:
diff --git a/ginac/color.cpp b/ginac/color.cpp
index 34ab4d8..bc240d6 100644
--- a/ginac/color.cpp
+++ b/ginac/color.cpp
@@ -100,4 +100,7 @@ return_type_t color::return_type_tinfo() const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(color)
+
 //////////
 // archiving
diff --git a/ginac/color.h b/ginac/color.h
index cf262a4..aff61ad 100644
--- a/ginac/color.h
+++ b/ginac/color.h
@@ -60,4 +60,5 @@ protected:
 	unsigned return_type() const { return return_types::noncommutative; }
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 
 	// non-virtual functions in this class
diff --git a/ginac/constant.cpp b/ginac/constant.cpp
index b230860..37300d8 100644
--- a/ginac/constant.cpp
+++ b/ginac/constant.cpp
@@ -216,12 +216,13 @@ bool constant::is_equal_same_type(const basic & other) const
 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;
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(constant)
+
 //////////
 // new virtual functions which can be overridden by derived classes
diff --git a/ginac/constant.h b/ginac/constant.h
index 33a7ffc..ca6e3cc 100644
--- a/ginac/constant.h
+++ b/ginac/constant.h
@@ -60,5 +60,6 @@ protected:
 	bool is_equal_same_type(const basic & other) const;
 	unsigned calchash() const;
-	
+	unsigned gethashseed() const;
+
 	// non-virtual functions in this class
 protected:
diff --git a/ginac/container.h b/ginac/container.h
index e2b0a94..3d6e6e5 100644
--- a/ginac/container.h
+++ b/ginac/container.h
@@ -28,4 +28,5 @@
 #include "archive.h"
 #include "assertion.h"
+#include "utils.h"
 
 #include <algorithm>
@@ -443,4 +444,5 @@ protected:
 
 	bool is_equal_same_type(const basic & other) const;
+	unsigned gethashseed() const DEFAULT_GETHASHSEED_BODY
 
 	// new virtual functions which can be overridden by derived classes
diff --git a/ginac/expairseq.cpp b/ginac/expairseq.cpp
index 7dc5582..bab4a99 100644
--- a/ginac/expairseq.cpp
+++ b/ginac/expairseq.cpp
@@ -31,5 +31,4 @@
 #include "operators.h"
 #include "utils.h"
-#include "hash_seed.h"
 #include "indexed.h"
 
@@ -616,5 +615,5 @@ unsigned expairseq::return_type() const
 unsigned expairseq::calchash() const
 {
-	unsigned v = make_hash_seed(typeid(*this));
+	unsigned v = gethashseed();
 	epvector::const_iterator i = seq.begin();
 	const epvector::const_iterator end = seq.end();
@@ -640,4 +639,7 @@ unsigned expairseq::calchash() const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(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
@@ -95,4 +95,5 @@ protected:
 	unsigned return_type() const;
 	unsigned calchash() const;
+	unsigned gethashseed() const;
 	ex expand(unsigned options=0) const;
 	
diff --git a/ginac/fail.cpp b/ginac/fail.cpp
index 79581f0..b24f080 100644
--- a/ginac/fail.cpp
+++ b/ginac/fail.cpp
@@ -48,4 +48,7 @@ DEFAULT_CTOR(fail)
 //////////
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(fail)
+
 DEFAULT_COMPARE(fail)
 DEFAULT_PRINT(fail, "FAIL")
diff --git a/ginac/fail.h b/ginac/fail.h
index 025d584..e5b773d 100644
--- a/ginac/fail.h
+++ b/ginac/fail.h
@@ -37,4 +37,5 @@ class fail : public basic
 protected:
 	unsigned return_type() const { return return_types::noncommutative_composite; };
+	unsigned gethashseed() const;
 
 	// non-virtual functions in this class
diff --git a/ginac/fderivative.cpp b/ginac/fderivative.cpp
index bb8dbd4..2fcce31 100644
--- a/ginac/fderivative.cpp
+++ b/ginac/fderivative.cpp
@@ -228,3 +228,6 @@ bool fderivative::match_same_type(const basic & other) const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(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
@@ -72,4 +72,5 @@ protected:
 	bool is_equal_same_type(const basic & other) const;
 	bool match_same_type(const basic & other) const;
+	unsigned gethashseed() const;
 
 	// non-virtual functions in this class
diff --git a/ginac/function.cppy b/ginac/function.cppy
index ce38045..dcd8b80 100644
--- a/ginac/function.cppy
+++ b/ginac/function.cppy
@@ -37,5 +37,4 @@
 #include "tostring.h"
 #include "utils.h"
-#include "hash_seed.h"
 #include "remember.h"
 
@@ -467,5 +466,6 @@ ex function::eval_ncmul(const exvector & v) const
 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++) {
 		v = rotate_left(v);
@@ -480,4 +480,8 @@ unsigned function::calchash() const
 }
 
+
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(function)
+
 ex function::thiscontainer(const exvector & v) const
 {
@@ -872,3 +876,2 @@ 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
@@ -245,4 +245,5 @@ protected:
 	unsigned return_type() const;
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 	
 	// new virtual functions which can be overridden by derived classes
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..3c512ad 100644
--- a/ginac/idx.cpp
+++ b/ginac/idx.cpp
@@ -28,5 +28,4 @@
 #include "archive.h"
 #include "utils.h"
-#include "hash_seed.h"
 
 #include <iostream>
@@ -352,5 +351,5 @@ unsigned idx::calchash() const
 	// dimensions or other attributes (variance etc.).
 	// 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);
 	v ^= value.gethash();
@@ -365,4 +364,7 @@ unsigned idx::calchash() const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(idx)
+
 /** By default, basic::evalf would evaluate the index value but we don't want
  *  a.1 to become a.(1.0). */
diff --git a/ginac/idx.h b/ginac/idx.h
index a5eda1a..d59edef 100644
--- a/ginac/idx.h
+++ b/ginac/idx.h
@@ -60,4 +60,5 @@ protected:
 	bool match_same_type(const basic & other) const;
 	unsigned calchash() const;
+	unsigned gethashseed() const;
 
 	// new virtual functions in this class
diff --git a/ginac/indexed.cpp b/ginac/indexed.cpp
index b85c386..c4589d7 100644
--- a/ginac/indexed.cpp
+++ b/ginac/indexed.cpp
@@ -338,4 +338,7 @@ unsigned indexed::return_type() const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(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
@@ -161,4 +161,5 @@ protected:
 	unsigned return_type() const;
 	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..8788860 100644
--- a/ginac/integral.cpp
+++ b/ginac/integral.cpp
@@ -439,4 +439,7 @@ return_type_t integral::return_type_tinfo() const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(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
@@ -54,4 +54,5 @@ public:
 	unsigned return_type() const;
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 	ex conjugate() const;
 	ex eval_integ() const;
diff --git a/ginac/matrix.cpp b/ginac/matrix.cpp
index 3e9b28b..1259e2d 100644
--- a/ginac/matrix.cpp
+++ b/ginac/matrix.cpp
@@ -319,4 +319,7 @@ bool matrix::match_same_type(const basic & other) const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(matrix)
+
 /** Automatic symbolic evaluation of an indexed matrix. */
 ex matrix::eval_indexed(const basic & i) const
diff --git a/ginac/matrix.h b/ginac/matrix.h
index d45e850..c8e2b66 100644
--- a/ginac/matrix.h
+++ b/ginac/matrix.h
@@ -133,4 +133,5 @@ protected:
 	bool match_same_type(const basic & other) const;
 	unsigned return_type() const { return return_types::noncommutative; };
+	unsigned gethashseed() const;
 	
 	// non-virtual functions in this class
diff --git a/ginac/mul.cpp b/ginac/mul.cpp
index 64660a2..68f398e 100644
--- a/ginac/mul.cpp
+++ b/ginac/mul.cpp
@@ -990,4 +990,7 @@ return_type_t mul::return_type_tinfo() const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(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
@@ -72,4 +72,5 @@ protected:
 	unsigned return_type() const;
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 	ex thisexpairseq(const epvector & v, const ex & oc, bool do_index_renaming = false) const;
 	ex thisexpairseq(std::auto_ptr<epvector> vp, const ex & oc, bool do_index_renaming = false) const;
diff --git a/ginac/ncmul.cpp b/ginac/ncmul.cpp
index a00a8de..396eafb 100644
--- a/ginac/ncmul.cpp
+++ b/ginac/ncmul.cpp
@@ -587,4 +587,7 @@ return_type_t ncmul::return_type_tinfo() const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(ncmul)
+
 //////////
 // new virtual functions which can be overridden by derived classes
diff --git a/ginac/ncmul.h b/ginac/ncmul.h
index 5c56e14..66ee2be 100644
--- a/ginac/ncmul.h
+++ b/ginac/ncmul.h
@@ -74,4 +74,5 @@ protected:
 	unsigned return_type() const;
 	return_type_t return_type_tinfo() const;
+	unsigned gethashseed() const;
 	
 	// new virtual functions which can be overridden by derived classes
diff --git a/ginac/numeric.h b/ginac/numeric.h
index 8cab801..ad3224d 100644
--- a/ginac/numeric.h
+++ b/ginac/numeric.h
@@ -132,5 +132,5 @@ protected:
 	bool is_equal_same_type(const basic &other) const;
 	unsigned calchash() const;
-	
+
 	// new virtual functions which can be overridden by derived classes
 	// (none)
diff --git a/ginac/power.cpp b/ginac/power.cpp
index 87792b9..d031d10 100644
--- a/ginac/power.cpp
+++ b/ginac/power.cpp
@@ -787,4 +787,7 @@ return_type_t power::return_type_tinfo() const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(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
@@ -81,4 +81,5 @@ protected:
 	unsigned return_type() const;
 	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..06b37ba 100644
--- a/ginac/pseries.cpp
+++ b/ginac/pseries.cpp
@@ -591,4 +591,7 @@ ex pseries::derivative(const symbol & s) const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(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
@@ -67,4 +67,5 @@ public:
 protected:
 	ex derivative(const symbol & s) const;
+	unsigned gethashseed() const;
 
 	// non-virtual functions in this class
diff --git a/ginac/relational.cpp b/ginac/relational.cpp
index 4ee87be..7a000a3 100644
--- a/ginac/relational.cpp
+++ b/ginac/relational.cpp
@@ -26,5 +26,4 @@
 #include "archive.h"
 #include "utils.h"
-#include "hash_seed.h"
 
 #include <iostream>
@@ -261,5 +260,6 @@ return_type_t relational::return_type_tinfo() const
 unsigned relational::calchash() const
 {
-	unsigned v = make_hash_seed(typeid(*this));
+	unsigned v = gethashseed();
+
 	unsigned lhash = lh.gethash();
 	unsigned rhash = rh.gethash();
@@ -298,4 +298,7 @@ unsigned relational::calchash() const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(relational)
+
 //////////
 // new virtual functions which can be overridden by derived classes
diff --git a/ginac/relational.h b/ginac/relational.h
index 0c0583c..a72a39f 100644
--- a/ginac/relational.h
+++ b/ginac/relational.h
@@ -71,4 +71,5 @@ protected:
 	return_type_t return_type_tinfo() const;
 	unsigned calchash() const;
+	unsigned gethashseed() const;
 
 	// new virtual functions which can be overridden by derived classes
diff --git a/ginac/structure.h b/ginac/structure.h
index 867cd42..61eea38 100644
--- a/ginac/structure.h
+++ b/ginac/structure.h
@@ -156,4 +156,5 @@ public:
 protected:
 	bool match_same_type(const basic & other) const { return true; }
+	unsigned gethashseed() const DEFAULT_GETHASHSEED_BODY
 public:
 
diff --git a/ginac/symbol.cpp b/ginac/symbol.cpp
index 4d73c9e..fba6c50 100644
--- a/ginac/symbol.cpp
+++ b/ginac/symbol.cpp
@@ -26,5 +26,4 @@
 #include "tostring.h"
 #include "utils.h"
-#include "hash_seed.h"
 #include "inifcns.h"
 
@@ -273,5 +272,5 @@ bool symbol::is_equal_same_type(const basic & other) const
 unsigned symbol::calchash() const
 {
-	unsigned seed = make_hash_seed(typeid(*this));
+	unsigned seed = gethashseed();
 	hashvalue = golden_ratio_hash(seed ^ serial);
 	setflag(status_flags::hash_calculated);
@@ -279,4 +278,7 @@ unsigned symbol::calchash() const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(symbol)
+
 //////////
 // virtual functions which can be overridden by derived classes
diff --git a/ginac/symbol.h b/ginac/symbol.h
index 519980f..e6216ef 100644
--- a/ginac/symbol.h
+++ b/ginac/symbol.h
@@ -66,5 +66,6 @@ protected:
 	bool is_equal_same_type(const basic & other) const;
 	unsigned calchash() const;
-	
+	unsigned gethashseed() const;
+
 	// non-virtual functions in this class
 public:
diff --git a/ginac/symmetry.cpp b/ginac/symmetry.cpp
index a44cfcc..197fd16 100644
--- a/ginac/symmetry.cpp
+++ b/ginac/symmetry.cpp
@@ -28,5 +28,4 @@
 #include "archive.h"
 #include "utils.h"
-#include "hash_seed.h"
 
 #include <functional>
@@ -188,5 +187,5 @@ int symmetry::compare_same_type(const basic & other) const
 unsigned symmetry::calchash() const
 {
-	unsigned v = make_hash_seed(typeid(*this));
+	unsigned v = gethashseed();
 
 	if (type == none) {
@@ -210,4 +209,7 @@ unsigned symmetry::calchash() const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(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
@@ -94,4 +94,5 @@ protected:
 	void do_print_tree(const print_tree & c, unsigned level) const;
 	unsigned calchash() const;
+	unsigned gethashseed() const;
 
 	// member variables
diff --git a/ginac/tensor.cpp b/ginac/tensor.cpp
index 42056ed..f02c4f1 100644
--- a/ginac/tensor.cpp
+++ b/ginac/tensor.cpp
@@ -571,4 +571,12 @@ bool tensepsilon::contract_with(exvector::iterator self, exvector::iterator othe
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(tensor)
+DEFAULT_GETHASHSEED(tensdelta)
+DEFAULT_GETHASHSEED(tensmetric)
+DEFAULT_GETHASHSEED(minkmetric)
+DEFAULT_GETHASHSEED(spinmetric)
+DEFAULT_GETHASHSEED(tensepsilon)
+
 //////////
 // global functions
diff --git a/ginac/tensor.h b/ginac/tensor.h
index fb8185b..e4a3f5a 100644
--- a/ginac/tensor.h
+++ b/ginac/tensor.h
@@ -39,4 +39,5 @@ class tensor : public basic
 protected:
 	unsigned return_type() const { return return_types::noncommutative_composite; }
+	unsigned gethashseed() const;
 
 	// non-virtual functions in this class
@@ -64,4 +65,5 @@ public:
 protected:
 	unsigned return_type() const { return return_types::commutative; }
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
 	void do_print_latex(const print_latex & c, unsigned level) const;
@@ -86,4 +88,5 @@ public:
 protected:
 	unsigned return_type() const { return return_types::commutative; }
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
 };
@@ -115,4 +118,5 @@ public:
 protected:
 	unsigned return_type() const { return return_types::commutative; }
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
 	void do_print_latex(const print_latex & c, unsigned level) const;
@@ -140,4 +144,5 @@ public:
 
 protected:
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
 	void do_print_latex(const print_latex & c, unsigned level) const;
@@ -170,4 +175,5 @@ public:
 protected:
 	unsigned return_type() const { return return_types::commutative; }
+	unsigned gethashseed() const;
 	void do_print(const print_context & c, unsigned level) const;
 	void do_print_latex(const print_latex & c, unsigned level) const;
diff --git a/ginac/utils.h b/ginac/utils.h
index 102f09d..f34cf7b 100644
--- a/ginac/utils.h
+++ b/ginac/utils.h
@@ -76,4 +76,16 @@ typedef unsigned long p_int;
 #endif
 
+/** 32 bit FNV-1a hash of a string. */
+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)
@@ -103,4 +115,31 @@ inline unsigned golden_ratio_hash(p_int n)
 }
 
+#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);
+	std::cout << "FAST " << tinfo.name() << " " << (const void*)tinfo.name() << "\n";
+	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
+static inline unsigned make_hash_seed(const std::type_info& tinfo)
+{
+	// type name is the same for all objects of the same type
+	std::cout << "SLOW " << tinfo.name() << " " << string_fnv_hash(tinfo.name()) << "\n";
+	return string_fnv_hash(tinfo.name());
+}
+
 /* Compute the sign of a permutation of a container, with and without an
    explicitly supplied comparison function. If the sign returned is 1 or -1,
@@ -426,4 +465,13 @@ int classname::compare_same_type(const basic & other) const \
 }
 
+#define DEFAULT_GETHASHSEED_BODY \
+{ \
+	static const unsigned seed = make_hash_seed(typeid(*this)); \
+	return seed; \
+}
+#define DEFAULT_GETHASHSEED(classname) \
+unsigned classname::gethashseed() const \
+DEFAULT_GETHASHSEED_BODY
+
 #define DEFAULT_PRINT(classname, text) \
 void classname::do_print(const print_context & c, unsigned level) const \
diff --git a/ginac/wildcard.cpp b/ginac/wildcard.cpp
index 6140fa5..de690b0 100644
--- a/ginac/wildcard.cpp
+++ b/ginac/wildcard.cpp
@@ -24,5 +24,4 @@
 #include "archive.h"
 #include "utils.h"
-#include "hash_seed.h"
 
 #include <iostream>
@@ -108,5 +107,5 @@ unsigned wildcard::calchash() const
 	// (golden_ratio_hash(typeid(*this).name()) ^ label)
 	// is not good enough yet...
-	unsigned seed = make_hash_seed(typeid(*this));
+	const unsigned seed = gethashseed();
 	hashvalue = golden_ratio_hash(seed ^ label);
 	setflag(status_flags::hash_calculated);
@@ -114,4 +113,7 @@ unsigned wildcard::calchash() const
 }
 
+/** overload hash seed for deterministic sorting */
+DEFAULT_GETHASHSEED(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
@@ -50,4 +50,5 @@ public:
 protected:
 	unsigned calchash() const;
+	unsigned gethashseed() const;
 
 	// non-virtual functions in this class
