31.08.2001 Ctors and multiple inheritance

	basic_letter
	      |
	letter
	      |
	unit_letter

	The ctor of unit_letter calls the ctor of its
	direct base (letter), which in turn calls
	the ctor of its own base (basic_letter).

	Calling the ctor of basic_letter directly in the 
	initialization list of a unit_letter leads
	to a compile time error.


	                 Zsum
	                /    \
	multiple_polylog      Euler_Zagier_sum
	      |         \    /
	harmonic_polylog multiple_zeta_value
	      |
	nielsen_polylog
	      |
	classical_polylog

	multiple_zeta_value has Zsum as a virtual base, therefore
	the ctor of multiple_zeta_value calls explicitly the ctor
	of Zsum in the initialization list.

	The ctors of harmonic_polylog, nielsen_polylog and classical_polylog
	all have the ctors of their direct bases as well as the ctor of Zsum
	in their initialization list. Without the explicit ctor of Zsum
	the default ctor for Zsum would be invoked.
	(Since the derived classes do not have any additional data members,
	only the ctor of Zsum seems sufficient.)

31.08.2001
	The following lines fail to contruct a classical_polylog
	
	letter l1(x,m1);
	classical_polylog CL1(lst(l1));

	The workaround are 

	classical_polylog CL1=classical_polylog(lst(l1));

	or

	lst temp_lst(l1);
	classical_polylog CL1(temp_lst);

31.08.2001
	Let class B be derived from class A.

	fct(const ex & expr)
	{
	 if ( is_ex_of_type(expr, B) )
	  { ... have type B ...}
	 else
	  { ... only type A ...}
	}

	ex x = B(...);

	A a = ex_to_A(x);

	fct(a);

	will execute the code for type A in fct.


04.09.2001
	The correct way to do it:

	ex x = B(...);

	A* ptr_to_A = static_cast<A *>(x.bp);

	ptr_to_A->virt_memb_fct(...);

	Here virt_memb_fct is a virtual member function of A.
	If it is reimplemented in B, the reimplementation is called
	in the example above.

31.10.2001
	subs substitues only syntactically. Consider the following:

	symbol a("a"), b("b");
	ex x = 1-a;
	ex f = 1-x;
	ex g = f.subs( x==b );

	yields g==a and not 1-b.

08.11.2001

	basic_letter l1 = basic_letter( (ex) 1, 1, 0, i);
	ex f1 = l1;    // both l1 and f1 are evaluated to a unit_letter
	               // status_flag "evaluated" is set
	
	basic_letter l2 = ex_to_basic_letter(f1); // this is just a static_cast
	                                          // does not change the status_flags
	                                          // therefore l2 prints out as a basic_letter
	ex f2 = l2;    // same story, "evaluated" still set and
	               // f2 prints out as basic_letter

	ex f3 = eval(l2); // now evaluation is forced and
	                  // f3 prints as a unit_letter

14.11.2001

	Simplifying expressions of the form "a-a" and hashvalues:

	GiNaC status flags:
	 0x01 dynallocated
	 0x02 evaluated
	 0x04 expanded
	 0x08 hash_calculated

	compare first checks the hashvalues, if they are not equal, the two
	objects are considered to be not equal.
	compare calls compare_same_type only if the hashvalues are equal

	The hashvalues is retrieved with the function gethash(), which in turn
	calls calchash().
	If the object is evaluated, the hashvalue is stored in
	 mutable unsigned hashvalue

	The methods append and prepend for lists do not update the hashvalues:

	symbol a("a"), b("b");
	ex f1 = lst(a);
	ex f2 = lst(a,b);
	cout << f1.gethash() << endl; // force hashvalue to be calculated
	cout << f2.gethash() << endl;
	f1 = ex_to_nonconst_lst(f1).append(b); // modify f1, f1 and f2 should be equal now
	cout << f1-f2 << endl;

26.11.2001

	subs is so slow !
	Using parameterized hash tables is therefore not practical.

20.12.2001

	Version 0.3.1 has some of its hash tables removed (due to
	inefficiency).

29.12.2001
	More on polymorphisms:
	Consider the following example
	
	  ex l_ex = unit_letter((ex) 1,n);
	  cout << l_ex << endl; // unit_letter::print is used

	  letter l2 = ex_to_letter(l_ex);
	  l2.print(print_context(cout)); // letter::print is used

	  const letter& l3 = ex_to_letter(l_ex);
	  l3.print(print_context(cout)); // unit_letter::print is used

	  ex_to_letter(l_ex).print(print_context(cout)); // unit_letter::print is used

	can use static_cast or dynamic_cast in ex_to_letter:
	
	  inline const letter &ex_to_letter(const ex &e)
	   {
	    return static_cast<const letter &>(*e.bp);
	   }                                                                                                                           
15.07.2002

	name clashes and templates:

	Suppose class A has a member letter of type ex, which
	is a smart pointer to a class letter.
	Furthermore, there is a template function
	 ex_to<T>(const T & ex)

	Then gcc-3.1 can not resolve the name conflict of

	 ex_to<letter>(letter)

16.07.2002
	helpers.cc: in nestedsums_helper_expand_power
	expansion starts now with 
	 create_Zsum(Infinity,_empty_list)
	instead of the (commutative) 1.

14.11.2002
	Replaced == by is_equal, where appropriate.
	This is necessary, since (x == 1) throws an exception,
	if x is non-commutative

25.08.2003
	Multiplication of list_of_tgamma: A list_of_tgamma carries
	not only the Gamma functions, but also an order variable,
	to which it will eventually expanded.

	A product of two list_of_tgamma has the order variable set to
	the one of the left factor.

	This makes the multiplication non-commutative.

	This feature is used in transcendental_sum_type_A-D in 
	distribute_over_subsum and distribute_over_subsum_rev.
	