Commits

Burcin Erocal committed 77adf47

Merge patches not related to order rewrite.

  • Participants
  • Parent commits 621d2d8

Comments (0)

Files changed (7)

File jpflori_compare_numeric.patch

-# HG changeset patch
-# Parent 687b580c8c7c209a148b9912e33e6d9c4e21d713
-diff --git a/ginac/numeric.cpp b/ginac/numeric.cpp
---- a/ginac/numeric.cpp
-+++ b/ginac/numeric.cpp
-@@ -756,6 +756,30 @@
-     }
-   }
- 
-+  int Number_T::compare_same_type(const Number_T& right) const { 
-+    verbose("compare_same_type");
-+    if (t != right.t) {
-+      Number_T a, b;
-+      coerce(a, b, *this, right);
-+      return a.compare_same_type(b);
-+    }
-+    switch(t) {
-+    case DOUBLE:
-+      return (v._double < right.v._double)?-1:(v._double > right.v._double);
-+    case LONG:
-+      return (v._long < right.v._long)?-1:(v._long > right.v._long);
-+    case PYOBJECT:
-+      int result;
-+      if (PyObject_Cmp(v._pyobject, right.v._pyobject, &result) == -1) {
-+	py_error("compare_same_type");
-+      }
-+      return result;
-+    default:
-+      stub("invalid type: compare_same_type type not handled");
-+    }
-+
-+  }
-+
-   bool Number_T::operator<=(const Number_T& right) const { 
-     verbose("operator<=");
-     if (t != right.t) {
-@@ -1696,10 +1720,8 @@
-   {
-     GINAC_ASSERT(is_exactly_a<numeric>(other));
-     const numeric &o = static_cast<const numeric &>(other);
--    int cmpval = (real() - o.real()).csgn();
--    if (cmpval != 0)
--	    return cmpval;
--    return (imag() - o.imag()).csgn();
-+
-+    return value.compare_same_type(o.value);
-   }
- 
- 
-diff --git a/ginac/numeric.h b/ginac/numeric.h
---- a/ginac/numeric.h
-+++ b/ginac/numeric.h
-@@ -114,6 +114,7 @@
-     operator long int() const;
- 
-     unsigned hash() const;
-+    int compare_same_type(const Number_T& right) const;
-     bool operator==(const Number_T& right) const;
-     bool operator!=(const Number_T& right) const;
-     bool operator<=(const Number_T& right) const;

File num_symbol.patch

-# HG changeset patch
-# Parent 7c20443cf59b8ec0d0b58b50a5fd5a69324666d0
-Add method to ex for counting number of symbols in an expression.
-
-diff --git a/ginac/ex.cpp b/ginac/ex.cpp
---- a/ginac/ex.cpp
-+++ b/ginac/ex.cpp
-@@ -21,6 +21,7 @@
-  */
- 
- #include "ex.h"
-+#include "symbol.h"
- #include "add.h"
- #include "mul.h"
- #include "ncmul.h"
-@@ -265,6 +266,18 @@
- 	}
- }
- 
-+size_t ex::nsymbols() const
-+{
-+	int res = 0;
-+	if (is_a<symbol>(*this)) {
-+		res=1;
-+	} else {
-+		for (size_t i=0; i < nops(); i++)
-+			res += op(i).nsymbols();
-+	}
-+	return res;
-+}
-+
- // private
- 
- /** Make this ex writable (if more than one ex handle the same basic) by 
-diff --git a/ginac/ex.h b/ginac/ex.h
---- a/ginac/ex.h
-+++ b/ginac/ex.h
-@@ -143,6 +143,7 @@
- 
- 	// operand access
- 	size_t nops() const { return bp->nops(); }
-+	size_t nsymbols() const;
- 	ex op(size_t i) const { return bp->op(i); }
- 	ex operator[](const ex & index) const { return (*bp)[index]; }
- 	ex operator[](size_t i) const { return (*bp)[i]; }

File pynac-pickle_symbolic_function.patch

-# HG changeset patch
-# Parent 687b580c8c7c209a148b9912e33e6d9c4e21d713
-Fix unarchiving of symbolic functions defined at runtime without any custom
-methods.
-
-Since the python_func member of function is a bitmask indicating which custom
-methods are defined in Python, symbolic functions defined at runtime are
-archived as regular GiNaC functions defined in C++. Unarchiving these later is
-not possible, as GiNaC does not expect any other functions than those already
-in the registry.
-
-Adding a Python callback to create a new symbolic function with the given and
-number of arguments if one is not found in the registry solves the unarchiving
-problem while keeping the archive/pickle format the same.
-
-diff --git a/ginac/function.cpp b/ginac/function.cpp
---- a/ginac/function.cpp
-+++ b/ginac/function.cpp
-@@ -580,7 +580,17 @@
- 			}
- 			++i; ++ser;
- 		}
--		throw (std::runtime_error("unknown function '" + s + "' in archive"));
-+		// if the name is not already in the registry, we are
-+		// unarchiving a SymbolicFunction without any custom methods
-+		// Call Python to create a new symbolic function with name s
-+		// and get the serial of this new SymbolicFunction
-+		ser = py_funcs.py_get_serial_for_new_sfunction(
-+				s, nargs);
-+		if (PyErr_Occurred()) {
-+		    throw(std::runtime_error("function::function archive error: cannot create new symbolic function " + s));
-+		}
-+		serial = ser;
-+		//throw (std::runtime_error("unknown function '" + s + "' in archive"));
- 	} else
- 		throw (std::runtime_error("unnamed function in archive"));
- 	}
-@@ -597,10 +607,12 @@
- {
- 	inherited::archive(n);
- 	GINAC_ASSERT(serial < registered_functions().size());
--	// we use different methods to archive function objects created at
--	// runtime and those created from c++
--	// the python_func flag indicates if we should use the python
--	// unpickling mechanism, or the regular unarchiving for c++ functions
-+	// we use Python's pickling mechanism to archive symbolic functions
-+	// with customized methods defined in Python. Symbolic functions
-+	// defined from c++ or those without custom methods are archived
-+	// directly, without calling Python. The python_func flag indicates if
-+	// we should use the python unpickling mechanism, or the regular
-+	// unarchiving for c++ functions.
- 	unsigned python_func = registered_functions()[serial].python_func;
- 	if (python_func) {
- 		n.add_unsigned("python", python_func);
-diff --git a/ginac/py_funcs.h b/ginac/py_funcs.h
---- a/ginac/py_funcs.h
-+++ b/ginac/py_funcs.h
-@@ -107,6 +107,7 @@
-     int (*py_get_ginac_serial)();
-     PyObject* (*py_get_sfunction_from_serial)(unsigned id);
-     unsigned (*py_get_serial_from_sfunction)(PyObject* f);
-+    unsigned (*py_get_serial_for_new_sfunction)(std::string &s, unsigned nargs);
- 
-     constant (*py_get_constant)(const char* name);
- 
-pynac-pickle_symbolic_function.patch
-jpflori_compare_numeric.patch
 trac9880_pynac_order_burcin_original.patch
 trac_9880-pynac_order_jp_new-p2.take2.patch
 trac_9880-cleanup.patch
-num_symbol.patch
 stable_op.patch
-trac_9880_ginac_infinities_rewrite.patch
 trac_9880_reviewer-vb.patch
 remove_compare.patch
 numerics.patch
 minus.patch
 minus_denom.patch
 mul_to_power.patch
-trac_11423_atan2.patch

File trac_11423_atan2.patch

-# HG changeset patch
-# Parent 7d268b3e86882289dd113430f7199243f247c439
-# HG changeset patch
-# Parent 7d268b3e86882289dd113430f7199243f247c439
-
-Trac #11432: Make atan2(0,0) throw error.
-diff --git a/ginac/inifcns_trans.cpp b/ginac/inifcns_trans.cpp
---- a/ginac/inifcns_trans.cpp
-+++ b/ginac/inifcns_trans.cpp
-@@ -1056,9 +1056,9 @@
- {
- 	if (y.is_zero()) {
- 
--		// atan2(0, 0) -> 0
-+		// atan2(0, 0) -> undefined
- 		if (x.is_zero())
--			return _ex0;
-+			throw (std::runtime_error("arctan2_eval(): arctan2(0,0) encountered"));
- 
- 		// atan2(0, x), x real and positive -> 0
- 		if (x.info(info_flags::positive))

File trac_9880_ginac_infinities_rewrite.patch

-# HG changeset patch
-# Parent 07780e7e129d3f5b572cefbd7ac24d3c8c604fe5
-# HG changeset patch
-# Parent aed6fef803be8eb290dcbb6e0e34e51abdb1b863
-
-Trac #9880: The pynac C++ part of the infinities rewrite
-
-diff --git a/.hgignore b/.hgignore
---- a/.hgignore
-+++ b/.hgignore
-@@ -3,6 +3,7 @@
- %*.o
- %*~
- %*.libs/
-+%*.rej
- Makefile
- config.guess
- config.sub
-@@ -11,3 +12,6 @@
- pynac.pc
- pynac.spec
- m4
-+install-sh
-+ltmain.sh
-+missing
-diff --git a/ginac/Makefile.am b/ginac/Makefile.am
---- a/ginac/Makefile.am
-+++ b/ginac/Makefile.am
-@@ -4,7 +4,7 @@
- lib_LTLIBRARIES = libpynac.la
- libpynac_la_SOURCES = py_funcs.cpp add.cpp archive.cpp basic.cpp clifford.cpp color.cpp \
-   constant.cpp ex.cpp expair.cpp expairseq.cpp exprseq.cpp \
--  fail.cpp fderivative.cpp function.cpp idx.cpp indexed.cpp inifcns.cpp \
-+  fail.cpp fderivative.cpp function.cpp idx.cpp indexed.cpp infinity.cpp inifcns.cpp \
-   inifcns_trans.cpp inifcns_gamma.cpp inifcns_nstdsums.cpp \
-   integral.cpp lst.cpp matrix.cpp mul.cpp ncmul.cpp normal.cpp numeric.cpp \
-   operators.cpp power.cpp registrar.cpp relational.cpp remember.cpp \
-@@ -22,7 +22,7 @@
- libpynac_la_LIBADD = $(PYTHON_LIBS)
- ginacincludedir = $(includedir)/pynac
- ginacinclude_HEADERS = ginac.h py_funcs.h add.h archive.h assertion.h basic.h class_info.h \
--  clifford.h color.h constant.h container.h ex.h expair.h expairseq.h \
-+  clifford.h color.h constant.h infinity.h container.h ex.h expair.h expairseq.h \
-   exprseq.h fail.h fderivative.h flags.h function.h hash_map.h idx.h indexed.h \
-   inifcns.h integral.h lst.h matrix.h mul.h ncmul.h normal.h numeric.h operators.h \
-   power.h print.h pseries.h ptr.h registrar.h relational.h structure.h \
-diff --git a/ginac/add.cpp b/ginac/add.cpp
---- a/ginac/add.cpp
-+++ b/ginac/add.cpp
-@@ -29,6 +29,7 @@
- #include "clifford.h"
- #include "ncmul.h"
- #include "constant.h"
-+#include "infinity.h"
- #include "compiler.h"
- #include "order.h"
- 
-@@ -398,7 +399,13 @@
- 		GINAC_ASSERT(seq.size()>1 || !overall_coeff.is_zero());
- 		return *this;
- 	}
--	
-+		
-+	// handle infinity
-+	for (epvector::const_iterator i = seq.begin(); i != seq.end(); i++)
-+		if (unlikely(is_exactly_a<infinity>(i->rest)))
-+			return eval_infinity(i);
-+
-+	/** Perform automatic term rewriting rules */
- 	int seq_size = seq.size();
- 	if (seq_size == 0) {
- 		// +(;c) -> c
-@@ -410,68 +417,21 @@
- 		throw (std::logic_error("add::eval(): sum of non-commutative objects has non-zero numeric term"));
- 	}
- 
--	// handle infinity
--	epvector::const_iterator last = seq.end();
--	epvector::const_iterator i = seq.begin();
--	ex pval = _ex0;
--	ex nval = _ex0;
--	for (; i != last; ++i) {
--		if ((i->rest).info(info_flags::infinity)) {
--			if (pval.is_equal(UnsignedInfinity)) {
--				throw(std::runtime_error("indeterminate expression: unsigned_infinity + x where x is Infinity, -Infinity or unsigned infinity encountered."));
--			}
--			if (i->rest.is_equal(UnsignedInfinity)) {
--				nval = i->rest;
--			} else if (ex_to<numeric>(i->coeff).is_real()) {
--				if (ex_to<numeric>(i->coeff).csgn() == -1) {
--					if (i->rest.is_equal(Infinity))
--						nval = NegInfinity;
--					else
--						nval = Infinity;
--				} else {
--					nval = i->rest;
--				}
--			} else {
--				nval = UnsignedInfinity;
--				if (!pval.is_zero()) {
--					throw(std::runtime_error("indeterminate expression: unsigned_infinity + x where x is Infinity, -Infinity or unsigned infinity encountered."));
--				}
--			}
--			if (!pval.is_zero()) {
--				if (!pval.is_equal(nval)) {
--					throw(std::runtime_error("indeterminate expression: Infinity - Infinity encountered."));
--				}
--			} else {
--				pval = nval;
--			}
--		}
--		
--	}
--	if(!pval.is_zero())
--		return pval;
--
- 	// if any terms in the sum still are purely numeric, then they are more
- 	// appropriately collected into the overall coefficient
--	//last = seq.end();
--	epvector::const_iterator j = seq.begin();
- 	int terms_to_collect = 0;
--	while (j != last) {
-+	for (epvector::const_iterator j = seq.begin(); j != seq.end(); j++)
- 		if (unlikely(is_a<numeric>(j->rest)))
- 			++terms_to_collect;
--		++j;
--	}
- 	if (terms_to_collect) {
- 		std::auto_ptr<epvector> s(new epvector);
- 		s->reserve(seq_size - terms_to_collect);
- 		numeric oc = *_num1_p;
--		j = seq.begin();
--		while (j != last) {
-+		for (epvector::const_iterator j = seq.begin(); j != seq.end(); j++)
- 			if (unlikely(is_a<numeric>(j->rest)))
- 				oc = oc.mul(ex_to<numeric>(j->rest)).mul(ex_to<numeric>(j->coeff));
- 			else
- 				s->push_back(*j);
--			++j;
--		}
- 		return (new add(s, ex_to<numeric>(overall_coeff).add_dyn(oc)))
- 		        ->setflag(status_flags::dynallocated);
- 	}
-@@ -479,6 +439,35 @@
- 	return this->hold();
- }
- 
-+
-+
-+namespace { // anonymous namespace
-+	infinity infinity_from_iter(epvector::const_iterator i)
-+	{
-+		GINAC_ASSERT(is_exactly_a<infinity>(i->rest));
-+		GINAC_ASSERT(is_a<numeric>(i->coeff));
-+		infinity result = ex_to<infinity>(i->rest);
-+		result *= i->coeff;
-+		return result;
-+	}
-+} // end anonymous namespace
-+
-+
-+ex add::eval_infinity(epvector::const_iterator infinity_iter) const
-+{
-+	GINAC_ASSERT(is_exactly_a<infinity>(infinity_iter->rest));
-+	infinity result = infinity_from_iter(infinity_iter);
-+
-+        for (epvector::const_iterator i = seq.begin(); i != seq.end(); i++) {
-+                if (not is_exactly_a<infinity>(i->rest)) continue;
-+                if (i == infinity_iter) continue;
-+		infinity i_infty = infinity_from_iter(i);
-+		result += i_infty;
-+        }
-+	return result;
-+}
-+
-+
- ex add::evalm() const
- {
- 	// Evaluate children first and add up all matrices. Stop if there's one
-diff --git a/ginac/add.h b/ginac/add.h
---- a/ginac/add.h
-+++ b/ginac/add.h
-@@ -77,6 +77,7 @@
- 	                                       const ex & c) const;
- 	ex recombine_pair_to_ex(const expair & p) const;
- 	ex expand(unsigned options=0) const;
-+	ex eval_infinity(epvector::const_iterator infinity_iter) const;
- 
- 	// non-virtual functions in this class
- protected:
-diff --git a/ginac/constant.cpp b/ginac/constant.cpp
---- a/ginac/constant.cpp
-+++ b/ginac/constant.cpp
-@@ -269,19 +269,4 @@
-  *  Calls python function py_eval_constant for evalf(). */
- const constant Catalan("catalan", ConstantEvalf, "G", domain::positive);
- 
--/** UnsignedInfinity. E.g., return value of gamma(-1).
-- *  Calls python function py_eval_unsigned_infinity for evalf(). */
--const constant UnsignedInfinity("Infinity", UnsignedInfinityEvalf, "\\infty",
--		domain::infinity);
--
--/** Infinity, i.e., positive infinity.
-- *  Calls python function py_eval_infinity for evalf(). */
--const constant Infinity("+Infinity", InfinityEvalf, "+\\infty",
--		domain::infinity);
--
--/** -Infinity, i.e., minus_infinity.
-- *  Calls python function py_eval_neg_infinity for evalf(). */
--const constant NegInfinity("-Infinity", NegInfinityEvalf, "-\\infty",
--		domain::infinity);
--
- } // namespace GiNaC
-diff --git a/ginac/constant.h b/ginac/constant.h
---- a/ginac/constant.h
-+++ b/ginac/constant.h
-@@ -83,9 +83,6 @@
- extern const constant Pi;
- extern const constant Catalan;
- extern const constant Euler;
--extern const constant UnsignedInfinity;
--extern const constant Infinity;
--extern const constant NegInfinity;
- 
- } // namespace GiNaC
- 
-diff --git a/ginac/expairseq.cpp b/ginac/expairseq.cpp
---- a/ginac/expairseq.cpp
-+++ b/ginac/expairseq.cpp
-@@ -32,6 +32,7 @@
- #include "utils.h"
- #include "indexed.h"
- #include "constant.h"
-+#include "infinity.h"
- 
- #include <iostream>
- #include <algorithm>
-diff --git a/ginac/ginac.h b/ginac/ginac.h
---- a/ginac/ginac.h
-+++ b/ginac/ginac.h
-@@ -33,6 +33,7 @@
- #include "print.h"
- 
- #include "constant.h"
-+#include "infinity.h"
- #include "fail.h"
- #include "integral.h"
- #include "lst.h"
-diff --git a/ginac/infinity.cpp b/ginac/infinity.cpp
-new file mode 100644
---- /dev/null
-+++ b/ginac/infinity.cpp
-@@ -0,0 +1,342 @@
-+/** @file infinity.cpp
-+ *
-+ *  Implementation of PyNaC's "infinity". */
-+
-+/*
-+ *  Copyright (C) 2011 Volker Braun <vbraun@stp.dias.ie>
-+ *
-+ *  This program is free software; you can redistribute it and/or modify
-+ *  it under the terms of the GNU General Public License as published by
-+ *  the Free Software Foundation; either version 2 of the License, or
-+ *  (at your option) any later version.
-+ *
-+ *  This program is distributed in the hope that it will be useful,
-+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ *  GNU General Public License for more details.
-+ *
-+ *  You should have received a copy of the GNU General Public License
-+ *  along with this program; if not, write to the Free Software
-+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-+ */
-+
-+#include "py_funcs.h"
-+#include "infinity.h"
-+#include "numeric.h"
-+#include "ex.h"
-+#include "archive.h"
-+#include "utils.h"
-+#include "add.h"
-+#include "mul.h"
-+#include "inifcns.h"
-+
-+#include <string>
-+#include <stdexcept>
-+#include <iostream>
-+
-+namespace GiNaC {
-+
-+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(infinity, basic,
-+  print_func<print_context>(&infinity::do_print).
-+  print_func<print_latex>(&infinity::do_print_latex).
-+  print_func<print_tree>(&infinity::do_print_tree).
-+  print_func<print_python_repr>(&infinity::do_print_python_repr))
-+
-+//////////
-+// default constructor
-+//////////
-+
-+// public
-+
-+infinity::infinity() 
-+: basic(&infinity::tinfo_static), direction(+1)
-+{
-+	setflag(status_flags::evaluated | status_flags::expanded);
-+}
-+
-+//////////
-+// other constructors
-+//////////
-+
-+// public
-+
-+infinity::infinity(const numeric & _direction)
-+: basic(&infinity::tinfo_static)
-+{
-+	// Note: we cannot accept an arbirtary ex as argument 
-+	// or we would take precedence over the copy constructor.
-+	set_direction(_direction);
-+	setflag(status_flags::evaluated | status_flags::expanded);
-+}
-+
-+infinity infinity::from_direction(const ex & _direction)
-+{
-+	GINAC_ASSERT(!is_a<infinity>(_direction));
-+	infinity result;
-+	result.set_direction(_direction);
-+	return result;
-+}
-+
-+infinity infinity::from_sign(int sgn)
-+{
-+	GINAC_ASSERT(sgn>=-1 and sgn<=1);
-+	infinity result;
-+	result.direction = sgn;
-+	return result;
-+}
-+
-+//////////
-+// archiving
-+//////////
-+
-+infinity::infinity(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst) {}
-+
-+ex infinity::unarchive(const archive_node &n, lst &sym_lst)
-+{
-+	ex value;
-+	if (n.find_ex("direction", value, sym_lst))
-+		return infinity::from_direction(value);
-+	else
-+		throw(std::runtime_error("infinity without direction in archive"));
-+}
-+
-+void infinity::archive(archive_node &n) const
-+{
-+	inherited::archive(n);
-+	n.add_ex("direction", direction);
-+}
-+
-+//////////
-+// functions overriding virtual functions from base classes
-+//////////
-+
-+// public
-+
-+void infinity::do_print(const print_context & c, unsigned level) const
-+{
-+	if (is_unsigned_infinity())
-+		c.s << "Infinity";
-+	else if (is_plus_infinity())
-+		c.s << "+Infinity";
-+	else if (is_minus_infinity())
-+		c.s << "-Infinity";
-+	else {
-+		c.s << "(";
-+		direction.print(c, level);
-+		c.s << ")*Infinity";
-+	}
-+}
-+
-+void infinity::do_print_tree(const print_tree & c, unsigned level) const
-+{
-+	c.s << std::string(level, ' ');
-+	if (is_unsigned_infinity())
-+		c.s << "unsigned_infinity";
-+	else
-+		c.s << "infinity";
-+	c.s << " (" << class_name() << ")" << " @" << this
-+	    << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
-+	    << std::endl;
-+	if (!is_unsigned_infinity())
-+		direction.print(c, level+4);
-+}
-+
-+void infinity::do_print_latex(const print_latex & c, unsigned level) const
-+{
-+	if (is_unsigned_infinity())
-+		c.s << "\\infty";
-+	else if (is_plus_infinity())
-+		c.s << "+\\infty";
-+	else if (is_minus_infinity())
-+		c.s << "-\\infty";
-+	else {
-+		c.s << "(";
-+		direction.print(c, level);
-+		c.s << ") \\infty";
-+	}
-+}
-+
-+void infinity::do_print_python_repr(const print_python_repr & c, unsigned level) const
-+{
-+	c.s << class_name() << "('" << "Infinity" << "'" << direction;
-+	c.s << ')';
-+}
-+
-+bool infinity::info(unsigned inf) const
-+{
-+	if (inf==info_flags::infinity)
-+		return true;
-+	if (inf == info_flags::real || 
-+	    inf == info_flags::positive ||
-+	    inf == info_flags::negative)
-+		return direction.info(inf);
-+	if (inf == info_flags::nonnegative)
-+		return direction.info(info_flags::positive);
-+	if (inf == info_flags::nonnegative)
-+		return direction.info(info_flags::positive);
-+	return inherited::info(inf);
-+}
-+
-+ex infinity::evalf(int level, PyObject* parent) const
-+{
-+	if (is_unsigned_infinity())
-+		return py_funcs.py_eval_unsigned_infinity();
-+	else if (is_plus_infinity())
-+		return py_funcs.py_eval_infinity();
-+	else if (is_minus_infinity())
-+		return py_funcs.py_eval_neg_infinity();
-+	return *this;
-+}
-+
-+ex infinity::conjugate() const
-+{
-+	return infinity::from_direction(direction.conjugate());
-+}
-+
-+ex infinity::real_part() const
-+{
-+	if (is_unsigned_infinity()) 
-+		throw(std::runtime_error("indeterminate expression: "
-+					 "real part of unsigned_infinity."));
-+	ex re_dir = direction.real_part();
-+	if (re_dir.is_zero()) return _ex0;
-+	return infinity::from_direction(re_dir);
-+}
-+
-+ex infinity::imag_part() const
-+{
-+	if (is_unsigned_infinity()) 
-+		throw(std::runtime_error("indeterminate expression: "
-+					 "imaginary part of unsigned_infinity."));
-+	ex im_dir = direction.imag_part();
-+	if (im_dir.is_zero()) return _ex0;
-+	return infinity::from_direction(im_dir);
-+}
-+
-+// protected
-+
-+ex infinity::derivative(const symbol & s) const
-+{
-+	return _ex0;
-+}
-+
-+int infinity::compare_same_type(const basic & other) const
-+{
-+	GINAC_ASSERT(is_exactly_a<infinity>(other));
-+	const infinity &o = static_cast<const infinity &>(other);
-+
-+	return direction.compare(o.direction);
-+}
-+
-+bool infinity::is_equal_same_type(const basic & other) const
-+{
-+	GINAC_ASSERT(is_exactly_a<infinity>(other));
-+	const infinity &o = static_cast<const infinity &>(other);
-+	return direction.is_equal(o.direction);
-+}
-+
-+unsigned infinity::calchash() const
-+{
-+	hashvalue = golden_ratio_hash((p_int)tinfo() ^ direction.gethash());
-+	setflag(status_flags::hash_calculated);
-+	return hashvalue;
-+}
-+
-+//////////
-+// new virtual functions which can be overridden by derived classes
-+//////////
-+
-+// none
-+
-+//////////
-+// non-virtual functions in this class
-+//////////
-+
-+bool infinity::is_unsigned_infinity() const 
-+{ 
-+	return direction.is_zero(); 
-+}
-+
-+
-+bool infinity::is_plus_infinity() const 
-+{ 
-+	return direction.is_equal(_ex1); 
-+}
-+
-+
-+bool infinity::is_minus_infinity() const 
-+{ 
-+	return direction.is_equal(_ex_1); 
-+}
-+
-+
-+void infinity::set_direction(const ex & new_direction)
-+{
-+	if (new_direction.is_zero())
-+		direction = _ex0;
-+	else {
-+		ex normalization = GiNaC::pow(GiNaC::abs(new_direction),-1);
-+		direction = mul(new_direction, normalization);
-+	}
-+}
-+
-+const infinity & infinity::operator *= (const ex & rhs)
-+{
-+	if (is_exactly_a<infinity>(rhs)) {
-+		const ex & rhs_direction = ex_to<infinity>(rhs).direction;
-+		set_direction(mul(direction, rhs_direction));
-+		return *this;
-+	}
-+	else if (rhs.is_zero())
-+		throw(std::runtime_error("indeterminate expression: "
-+					 "0 * infinity encountered."));
-+	else if (rhs.info(info_flags::positive)) {
-+		return *this;
-+	} else if (rhs.info(info_flags::negative)) {
-+		direction = mul(-1, direction);
-+		return *this;
-+	} else if (rhs.nsymbols()==0) {
-+		set_direction(mul(direction, rhs));
-+		return *this;
-+	}
-+	throw(std::runtime_error("indeterminate expression: "
-+				 "infinity * f(x) encountered."));
-+}
-+
-+
-+const infinity & infinity::operator += (const ex & rhs)
-+{
-+	if (not is_exactly_a<infinity>(rhs))
-+		return *this;
-+	const ex & rhs_direction = ex_to<infinity>(rhs).direction;
-+	if (not direction.is_equal(rhs_direction) )
-+		if (ex_to<infinity>(rhs).is_unsigned_infinity() or is_unsigned_infinity())
-+			throw(std::runtime_error("indeterminate expression: "
-+						 "unsigned_infinity +- infinity encountered."));
-+		else
-+			throw(std::runtime_error("indeterminate expression: "
-+						 "infinity - infinity encountered."));
-+	return *this;
-+}
-+
-+
-+//////////
-+// global "infinity" constants
-+//////////
-+
-+/** Infinity, i.e., positive infinity.
-+ *  Calls python function py_eval_infinity for evalf(). */
-+const infinity Infinity = infinity::from_sign(+1);
-+
-+
-+/** Infinity, i.e., positive infinity.
-+ *  Calls python function py_eval_infinity for evalf(). */
-+const infinity NegInfinity = infinity::from_sign(-1);
-+
-+
-+/** UnsignedInfinity. E.g., return value of gamma(-1).
-+ *  Calls python function py_eval_unsigned_infinity for evalf(). */
-+const infinity UnsignedInfinity = infinity::from_sign(0);
-+
-+
-+} // namespace GiNaC
-diff --git a/ginac/infinity.h b/ginac/infinity.h
-new file mode 100644
---- /dev/null
-+++ b/ginac/infinity.h
-@@ -0,0 +1,86 @@
-+/** @file infinity.h
-+ *
-+ *  The value "Infinity".  */
-+
-+/*
-+ *  Copyright (C) 2011 Volker Braun <vbraun@stp.dias.ie>
-+ *
-+ *  This program is free software; you can redistribute it and/or modify
-+ *  it under the terms of the GNU General Public License as published by
-+ *  the Free Software Foundation; either version 2 of the License, or
-+ *  (at your option) any later version.
-+ *
-+ *  This program is distributed in the hope that it will be useful,
-+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ *  GNU General Public License for more details.
-+ *
-+ *  You should have received a copy of the GNU General Public License
-+ *  along with this program; if not, write to the Free Software
-+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-+ */
-+
-+#ifndef __GINAC_INFINITY_H__
-+#define __GINAC_INFINITY_H__
-+
-+#include "basic.h"
-+#include "numeric.h"
-+#include "ex.h"
-+
-+#include <string>
-+
-+namespace GiNaC {
-+
-+	
-+/** This class holds "infinity"
-+ *  It includes a direction (like -infinity).
-+ **/
-+class infinity : public basic
-+{
-+	GINAC_DECLARE_REGISTERED_CLASS(infinity, basic)
-+public:
-+       	infinity(const numeric & _direction);
-+	static infinity from_direction(const ex & _direction);
-+	static infinity from_sign(int sgn);
-+	
-+	// functions overriding virtual functions from base classes
-+public:
-+	bool info(unsigned inf) const;
-+	ex evalf(int level = 0, PyObject* parent=NULL) const;
-+	ex conjugate() const;
-+	ex real_part() const;
-+	ex imag_part() const;
-+
-+	bool is_unsigned_infinity() const;
-+	bool is_plus_infinity() const;
-+	bool is_minus_infinity() const;
-+	const ex & get_direction() const { return direction; };
-+	const infinity & operator *= (const ex & rhs);
-+	const infinity & operator += (const ex & rhs);
-+
-+protected:
-+	ex derivative(const symbol & s) const;
-+	bool is_equal_same_type(const basic & other) const;
-+	unsigned calchash() const;
-+	
-+	// non-virtual functions in this class
-+protected:
-+	void do_print(const print_context & c, unsigned level) const;
-+	void do_print_tree(const print_tree & c, unsigned level) const;
-+	void do_print_latex(const print_latex & c, unsigned level) const;
-+	void do_print_python_repr(const print_python_repr & c, unsigned level) const;
-+
-+	void set_direction(const ex & new_direction);
-+	
-+// member variables
-+private:
-+	ex direction;
-+};
-+
-+extern const infinity Infinity;
-+extern const infinity NegInfinity;
-+extern const infinity UnsignedInfinity;
-+
-+} // namespace GiNaC
-+
-+#endif // ndef __GINAC_INFINITY_H__
-diff --git a/ginac/inifcns_gamma.cpp b/ginac/inifcns_gamma.cpp
---- a/ginac/inifcns_gamma.cpp
-+++ b/ginac/inifcns_gamma.cpp
-@@ -23,6 +23,7 @@
- 
- #include "inifcns.h"
- #include "constant.h"
-+#include "infinity.h"
- #include "pseries.h"
- #include "numeric.h"
- #include "power.h"
-diff --git a/ginac/inifcns_nstdsums.cpp b/ginac/inifcns_nstdsums.cpp
---- a/ginac/inifcns_nstdsums.cpp
-+++ b/ginac/inifcns_nstdsums.cpp
-@@ -68,6 +68,7 @@
- 
- #include "add.h"
- #include "constant.h"
-+#include "infinity.h"
- #include "lst.h"
- #include "mul.h"
- #include "numeric.h"
-diff --git a/ginac/inifcns_trans.cpp b/ginac/inifcns_trans.cpp
---- a/ginac/inifcns_trans.cpp
-+++ b/ginac/inifcns_trans.cpp
-@@ -24,6 +24,7 @@
- #include "inifcns.h"
- #include "ex.h"
- #include "constant.h"
-+#include "infinity.h"
- #include "numeric.h"
- #include "power.h"
- #include "operators.h"
-diff --git a/ginac/mul.cpp b/ginac/mul.cpp
---- a/ginac/mul.cpp
-+++ b/ginac/mul.cpp
-@@ -31,6 +31,7 @@
- #include "symbol.h"
- #include "compiler.h"
- #include "constant.h"
-+#include "infinity.h"
- #include "function.h"
- #include "inifcns.h"
- #include "order.h"
-@@ -614,9 +615,11 @@
- 		    print(print_tree(std::cerr));
- 		GINAC_ASSERT(!is_exactly_a<numeric>(recombine_pair_to_ex(*i)));
- 		/* for paranoia */
--		expair p = split_ex_to_pair(recombine_pair_to_ex(*i));
--		GINAC_ASSERT(p.rest.is_equal(i->rest));
--		GINAC_ASSERT(p.coeff.is_equal(i->coeff));
-+		//   The following test will fail on sage: exp(x)*exp(x)
-+		//   Thats probably not an issue, but should be investigated.
-+		// expair p = split_ex_to_pair(recombine_pair_to_ex(*i));
-+		// GINAC_ASSERT(p.rest.is_equal(i->rest));
-+		// GINAC_ASSERT(p.coeff.is_equal(i->coeff));
- 		/* end paranoia */
- 		++i;
- 	}
-@@ -627,53 +630,30 @@
- 		GINAC_ASSERT(seq.size()>1 || !overall_coeff.is_equal(_ex1));
- 		return *this;
- 	}
--	
-+
-+	// handle infinity and handle exp(a)*exp(b) -> exp(a+b) and
-+	unsigned exp_count = 0;
-+	for (epvector::const_iterator i = seq.begin(); i != seq.end(); i++) {
-+		const numeric& coeff = ex_to<numeric>(i->coeff);
-+		if (unlikely(is_exactly_a<infinity>(i->rest)))
-+			return eval_infinity(i);
-+		if (unlikely(is_ex_the_function(i->rest, exp) and
-+			     coeff.is_integer())) {
-+			exp_count++;
-+			if (exp_count>1 or not coeff.is_equal(*_num1_p))
-+				return eval_exponentials();
-+		}
-+	}
-+
-+	// perform the remaining automatic rewrites
- 	size_t seq_size = seq.size();
- 	if (overall_coeff.is_zero()) {
- 		// *(...,x;0) -> 0
--		// unless an element of seq is infinity
--		epvector::const_iterator last = seq.end();
--		epvector::const_iterator i = seq.begin();
--		for (; i != last; ++i) {
--			if (i->rest.info(info_flags::infinity) && 
--					is_a<numeric>(i->coeff) && 
--					ex_to<numeric>(i->coeff).csgn() == 1) {
--				throw(std::runtime_error("indeterminate expression: 0*infinity encountered."));
--			}
--		}
- 		return _ex0;
- 	} else if (seq_size==0) {
- 		// *(;c) -> c
- 		return overall_coeff;
--	} else if (seq_size==1 && seq[0].rest.info(info_flags::infinity)) {
--		if (!ex_to<numeric>(overall_coeff).is_real()) {
--			throw(std::domain_error("x*Infinity with non real x encountered."));
--		} else if (!is_a<numeric>(seq[0].coeff) || 
--				!ex_to<numeric>(seq[0].coeff).is_real()) {
--				throw(std::domain_error("power::eval(): pow(Infinity, x) for non real x is not defined."));
--		} else if (ex_to<numeric>(seq[0].coeff).csgn() == -1) {
--			return _ex0;
--		} else if (seq[0].rest.is_equal(UnsignedInfinity)) {
--			return UnsignedInfinity;
--		}
--		bool overall_sign=(ex_to<numeric>(overall_coeff).csgn() == -1);
--		if (overall_sign) {
--			if (seq[0].rest.is_equal(NegInfinity)) {
--				if (ex_to<numeric>(seq[0].coeff).is_even()) {
--					return NegInfinity;
--				} else
--					return Infinity;
--			} else
--				return NegInfinity;
--		} else {
--			if (seq[0].rest.is_equal(NegInfinity) && 
--				ex_to<numeric>(seq[0].coeff).is_even()) {
--					return Infinity;
--			} else
--				return seq[0].rest;
--		}
--	} else if (seq_size==1 && overall_coeff.is_equal(_ex1) && \
--			!ex_to<numeric>(overall_coeff).is_parent_pos_char()) {
-+	} else if (seq_size==1 && overall_coeff.is_equal(_ex1)) {
- 		// *(x;1) -> x
- 		return recombine_pair_to_ex(*(seq.begin()));
- 	} else if ((seq_size==1) &&
-@@ -692,25 +672,9 @@
- 		                ex_to<numeric>(addref.overall_coeff).
- 		                mul_dyn(ex_to<numeric>(overall_coeff)))
- 		       )->setflag(status_flags::dynallocated | status_flags::evaluated);
--	} else if ((seq_size==1) && 
--			is_ex_the_function((*seq.begin()).rest, exp) &&
--			ex_to<numeric>((*seq.begin()).coeff).is_integer() &&
--			!(*seq.begin()).coeff.is_equal(_ex1) ) {
--		// even though exp defines a power simplification rule,
--		// it is possible to end up with i->coeff != 1, e.g.,
--		// as a result of construct_from_2_ex
--		ex new_exp = pow((*seq.begin()).rest, (*seq.begin()).coeff);
--		if (is_a<numeric>(new_exp)) {
--			return ex_to<numeric>(overall_coeff).mul(
--					ex_to<numeric>(new_exp));
--		}
--		return (new mul(new_exp, ex_to<numeric>(overall_coeff))
--			       )->setflag(status_flags::dynallocated);
- 	} else if ((seq_size >= 2) && (! (flags & status_flags::expanded))) {
- 		// Strip the content and the unit part from each term. Thus
- 		// things like (-x+a)*(3*x-3*a) automagically turn into - 3*(x-a)2
--		// also handles exp(a)*exp(b) -> exp(a+b) and
--		// various combinations of infinity
- 
- 		epvector::const_iterator last = seq.end();
- 		epvector::const_iterator i = seq.begin();
-@@ -718,89 +682,12 @@
- 		std::auto_ptr<epvector> s(new epvector);
- 		numeric oc = *_num1_p;
- 		bool something_changed = false;
--		// in order to simplify exp(a)*exp(b) -> exp(a + b)
--		// we keep track of the final exp argument
--		ex exp_arg = _ex0;
--		// for efficiency we only modify the expression for the exp
--		// simplification above if there is more than one exp
--		unsigned exp_count = 0;
--		// we use pval to store the previously encountered infinity type
--		//  0 means we have 1/infinity
--		//  1 means we didn't run into infinity
--		ex pval = _ex1;
--		ex nval = _ex1;
- 		while (i!=last) {
--			if (unlikely((i->rest).info(info_flags::infinity))) {
--				if (is_a<numeric>(i->coeff) &&
--					ex_to<numeric>(i->coeff).is_real()) {
--					if (ex_to<numeric>(i->coeff).csgn() ==
--							-1){
--						nval = _ex0;
--					}
--					else if (i->rest.is_equal(NegInfinity) 
--							&& ex_to<numeric>(
--							    i->coeff).is_even())
--						nval = Infinity;
--					else
--						nval = i->rest;
--				} else
--					throw(std::domain_error("power::eval(): pow(Infinity, x) for non real x is not defined."));
--				if (nval.is_zero()) {
--					if (!(pval.is_zero() || 
--							pval.is_equal(_ex1)))
--						throw(std::runtime_error("indeterminate expression: infinity/infinity encountered."));
--					else
--						pval = _ex0;
--				} else if (nval.is_equal(UnsignedInfinity) ||
--						pval.is_equal(UnsignedInfinity))
--					pval = UnsignedInfinity;
--				else if (pval.is_equal(_ex1))
--					pval = nval;
--				else if (nval.is_equal(pval))
--					pval = Infinity;
--				else
--					pval = NegInfinity;
--			}
--			if (unlikely(is_ex_the_function(i->rest, exp) &&
--					ex_to<numeric>(i->coeff).is_integer())) {
--				// if the power of first exp is != 1 we still
--				// have to modify the arguments list
--				// incrementing exp_count one more will
--				// trigger this
--				if (exp_count == 0 && !i->coeff.is_equal(_ex1)){
--					s->push_back(*i);
--					exp_count += 1;
--				}
--				exp_count += 1;
--				exp_arg += i->rest.op(0)*i->coeff;
--				if (exp_count > 1) {
--					// there is more than one exp,
--					// we will change the structure of this
--					// mul instance, create a new epvector
--					// for the argument if there isn't one
--					// already so we can skip this and
--					// future exp's
--
--					if (! something_changed) {
--						s->reserve(seq_size);
--						something_changed = true;
--					}
--
--					while ((j!=i) && (j!=last)) {
--						s->push_back(*j);
--						++j;
--					}
--					++i;
--					++j;
--					continue;
--				}
--
--				// first encounter of an exp, just continue
-+			if (likely(! (is_a<add>(i->rest) && i->coeff.is_equal(_ex1)))) {
-+				// power::eval has such a rule, no need to handle powers here
- 				++i;
- 				continue;
--			} else if (unlikely(is_a<add>(i->rest) &&
--						i->coeff.is_equal(_ex1))){
--
-+			}
- 
- 			// XXX: What is the best way to check if the polynomial is a primitive? 
- 			numeric c = i->rest.integer_content();
-@@ -847,56 +734,12 @@
- 
- 			++i;
- 			++j;
--			continue;
--			}
--			++i;
--		}
--		if (!pval.is_equal(_ex1)) {
--			if (!ex_to<numeric>(overall_coeff).is_real()) {
--				throw(std::domain_error("x*Infinity with non real x encountered."));
--			} else if (pval.is_zero() || 
--					pval.is_equal(UnsignedInfinity))
--				return pval;
--			else if (ex_to<numeric>(overall_coeff).csgn() == -1)
--				return -pval;
--			else
--				return pval;
- 		}
- 		if (something_changed) {
- 			while (j!=last) {
- 				s->push_back(*j);
- 				++j;
- 			}
--			if (exp_count > 1) {
--				// there was more than one exp
--				// find the already existing exp in the args
--				epvector::iterator prev_exp;
--				prev_exp = s->begin();
--				while( prev_exp != s->end() ) {
--					if (is_ex_the_function(prev_exp->rest,
--						exp) && ex_to<numeric>\
--							(prev_exp->coeff)\
--							.is_integer())
--						break;
--					++prev_exp;
--				}
--				if (prev_exp == s->end())
--					throw(std::runtime_error("Cannot find previous exp while simplifying mul"));
--
--				// see what the new value of exp will be
--				ex new_exp = exp(exp_arg);
--				if (is_a<numeric>(new_exp)) {
--					// if it is a numeric
--					// multiply overall coeff with the new
--					// value, remove the existing exp
--					s->erase(prev_exp);
--					oc = oc.mul(ex_to<numeric>(new_exp));
--				} else {
--					// just set prev_exp to the new value
--					prev_exp->rest = new_exp;
--					prev_exp->coeff = _ex1;
--				}
--			}
- 			if (s->empty()) {
- 				return ex_to<numeric>(overall_coeff).mul_dyn(oc);
- 			}
-@@ -904,9 +747,53 @@
- 			       )->setflag(status_flags::dynallocated);
- 		}
- 	}
--
-+	
- 	return this->hold();
- }
-+	
-+
-+
-+ex mul::eval_exponentials() const
-+{
-+	ex exp_arg = _ex0;
-+	numeric oc = *_num1_p;
-+	std::auto_ptr<epvector> s(new epvector);
-+	s->reserve(seq.size());
-+
-+	for (epvector::const_iterator i = seq.begin(); i != seq.end(); i++) {
-+		const numeric & coeff = ex_to<numeric>(i->coeff);
-+		const bool simplifyable_exp = is_ex_the_function(i->rest, exp) and coeff.is_integer();
-+		if (likely(not simplifyable_exp))
-+			s->push_back(*i);
-+		else
-+			exp_arg += i->rest.op(0) * coeff;
-+	}
-+
-+	ex new_exp = exp(exp_arg);
-+	if (is_a<numeric>(new_exp))
-+		oc = oc.mul(ex_to<numeric>(new_exp));
-+	else
-+		s->push_back(expair(new_exp, _ex1));
-+
-+	mul * result = new mul(s, ex_to<numeric>(overall_coeff).mul_dyn(oc));
-+	return result->setflag(status_flags::dynallocated);
-+}
-+
-+
-+ex mul::eval_infinity(epvector::const_iterator infinity_iter) const
-+{
-+	GINAC_ASSERT(is_exactly_a<infinity>(infinity_iter->rest));
-+	GINAC_ASSERT(infinity_iter->coeff.is_equal(_ex1));
-+	infinity result = ex_to<infinity>(recombine_pair_to_ex(*infinity_iter));
-+	result *= overall_coeff;
-+
-+        for (epvector::const_iterator i = seq.begin(); i != seq.end(); i++) {
-+                if (i == infinity_iter) continue;
-+		result *= recombine_pair_to_ex(*i);
-+        }
-+	return result;
-+}
-+
- 
- ex mul::evalf(int level, PyObject* parent) const
- {
-diff --git a/ginac/mul.h b/ginac/mul.h
---- a/ginac/mul.h
-+++ b/ginac/mul.h
-@@ -87,7 +87,9 @@
- 	ex expand(unsigned options=0) const;
- 	void find_real_imag(ex&, ex&) const;
- 	//int compare(const basic& other) const;
--	
-+	ex eval_infinity(epvector::const_iterator infinity_iter) const;
-+	ex eval_exponentials() const;
-+
- 	// new virtual functions which can be overridden by derived classes
- 	// none
- 	
-diff --git a/ginac/power.cpp b/ginac/power.cpp
---- a/ginac/power.cpp
-+++ b/ginac/power.cpp
-@@ -28,6 +28,7 @@
- #include "ncmul.h"
- #include "numeric.h"
- #include "constant.h"
-+#include "infinity.h"
- #include "operators.h"
- #include "inifcns.h" // for log() in power::derivative() and exp for printing
- #include "matrix.h"
-@@ -466,53 +467,38 @@
- 	}
- 
- 	// ^(\infty, x)
--	// error if x is not numeric and real
--	// -> 0 if x < 0
--	// -> error if x == 0
--	// -> Infinity if \infty is NegInfinity and x is even
--	// -> \infty otherwise
--	if (ebasis.info(info_flags::infinity)) {
--		if (exponent_is_numerical) {
--			if (!num_exponent->is_real()) {
--				throw(std::domain_error("power::eval(): pow(Infinity, x) is not defined for complex x."));
--			} else if (num_exponent->csgn() == -1)
--				return _ex0;
--			else if (num_exponent->is_zero())
--				throw(std::domain_error("power::eval(): pow(Infinity, 0) is undefined."));
--			else if (ebasis.is_equal(NegInfinity) && 
--					num_exponent->is_even())
-+	if (is_a<infinity>(ebasis)) {
-+		const infinity & basis_inf = ex_to<infinity>(ebasis);
-+		if (eexponent.nsymbols()>0)
-+			throw(std::domain_error("power::eval(): pow(Infinity, f(x)) is not defined."));
-+		if (eexponent.is_zero())
-+			throw(std::domain_error("power::eval(): pow(Infinity, 0) is undefined."));
-+		if (eexponent.info(info_flags::negative))
-+			return _ex0;
-+		if (eexponent.info(info_flags::positive))
-+			if (basis_inf.is_plus_infinity())
- 				return Infinity;
- 			else
--				return ebasis;
--		} else
--			throw(std::domain_error("power::eval(): pow(Infinity, x) for non numeric x is not defined."));
-+				return UnsignedInfinity;
-+		throw(std::domain_error("power::eval(): pow(Infinity, c)"
-+					" for constant of undetermined sign is not defined."));
- 	}
-+
- 	// ^(x, \infty)
--	// error if x is not numeric
--	// error if \infty is UnsignedInfinity
--	// error if x \in {0, 1, -1}
--	// 0 if \infty is NegInfinity
--	// UnsignedInfinity if x < 0
--	// Infinity otherwise
--	if (eexponent.info(info_flags::infinity)) {
--		if (!basis_is_numerical) {
--			throw(std::domain_error("power::eval(): pow(x, Infinity) for non numeric x is not defined."));
--		} else if (!num_basis->is_real()) {
--			throw(std::domain_error("power::eval(): pow(x, Infinity) for non real x is not defined."));
--		} else if (ebasis.is_equal(UnsignedInfinity)) {
--			throw(std::domain_error("power::eval(): pow(x, UnsignedInfinity) is not defined."));
--		} else if (num_basis->is_zero()) {
--			throw(std::domain_error("power::eval(): pow(0, Infinity) is not defined."));
--		} else if (num_basis->is_equal(*_num1_p) || 
--				num_basis->is_equal(*_num_1_p)) {
-+	if (is_a<infinity>(eexponent)) {
-+		const infinity & exp_inf = ex_to<infinity>(eexponent);
-+		if (exp_inf.is_unsigned_infinity())
-+			throw(std::domain_error("power::eval(): pow(x, unsigned_infinity) is not defined."));
-+		if (ebasis.nsymbols()>0) 
-+			throw(std::domain_error("power::eval(): pow(f(x), infinity) is not defined."));
-+		// x^(c*oo) --> (x^c)^(+oo)
-+		const ex abs_base = abs(pow(ebasis, exp_inf.get_direction()));
-+		if (abs_base > _ex1) return Infinity;
-+		if (abs_base < _ex1) return _ex0;
-+		if (abs_base == _ex1)
- 			throw(std::domain_error("power::eval(): pow(1, Infinity) is not defined."));
--		} else if (eexponent.is_equal(NegInfinity)) {
--			return _ex0;
--		} else if (num_basis->csgn() == -1) {
--			return UnsignedInfinity;
--		} else {
--			return Infinity;
--		}
-+		throw(std::domain_error("power::eval(): pow(c, Infinity)"
-+					" for unknown magnitude |c| is not defined."));
- 	}
- 	
- 	// ^(x,0) -> 1  (0^0 also handled here)
-diff --git a/ginac/relational.cpp b/ginac/relational.cpp
---- a/ginac/relational.cpp
-+++ b/ginac/relational.cpp
-@@ -20,11 +20,13 @@
-  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-  */
- 
-+#include "compiler.h"
- #include "relational.h"
- #include "operators.h"
- #include "numeric.h"
- #include "archive.h"
- #include "utils.h"
-+#include "infinity.h"
- 
- #include <iostream>
- #include <stdexcept>
-@@ -381,6 +383,27 @@
-  *  unequal or undecidable). */
- relational::operator relational::safe_bool() const
- {
-+	if (unlikely(is_exactly_a<infinity>(rh) and is_exactly_a<infinity>(lh))) {
-+		const infinity & lh_inf = ex_to<infinity>(lh);
-+		const infinity & rh_inf = ex_to<infinity>(rh);
-+		const ex df = lh_inf.get_direction() - rh_inf.get_direction();
-+		switch (o) {
-+		case equal:
-+			return make_safe_bool(ex_to<numeric>(df).is_zero());
-+		case not_equal:
-+			return make_safe_bool(!ex_to<numeric>(df).is_zero());
-+		case less:
-+		case less_or_equal:
-+			return make_safe_bool(lh_inf.is_minus_infinity() and rh_inf.is_plus_infinity());
-+		case greater:
-+		case greater_or_equal:
-+			return make_safe_bool(lh_inf.is_plus_infinity() and rh_inf.is_minus_infinity());
-+		default:
-+			throw(std::logic_error("invalid relational operator"));
-+		}
-+		return make_safe_bool(false);
-+	}
-+
- 	const ex df = lh-rh;
- 	if (!is_exactly_a<numeric>(df))
- 		// cannot decide on non-numerical results
-@@ -404,4 +427,7 @@
- 	}
- }
- 
-+
-+
-+
- } // namespace GiNaC

File trac_9880_reviewer-vb.patch

  	ex overall_coeff;
  #if EXPAIRSEQ_USE_HASHTAB
  	epplistvector hashtab;
-diff --git a/ginac/inifcns_trans.cpp b/ginac/inifcns_trans.cpp
---- a/ginac/inifcns_trans.cpp
-+++ b/ginac/inifcns_trans.cpp
-@@ -1107,6 +1107,23 @@
- 	    is_a<numeric>(x) && !x.info(info_flags::crational))
- 		return atan(ex_to<numeric>(y), ex_to<numeric>(x));
- 
-+	// handle infinities
-+	if (is_a<infinity>(x) || is_a<infinity>(y)) {
-+		if (is_a<infinity>(x) && ex_to<infinity>(x).is_unsigned_infinity())
-+			throw (std::runtime_error("arctan2_eval(): arctan2(unsigned_infinity, x) encountered"));
-+		if (is_a<infinity>(y) && ex_to<infinity>(y).is_unsigned_infinity())
-+			throw (std::runtime_error("arctan2_eval(): arctan2(x, unsigned_infinity) encountered"));
-+
-+		if (is_a<infinity>(x) && is_a<infinity>(y)) 
-+			return atan2_eval(ex_to<infinity>(x).get_direction(), 
-+					  ex_to<infinity>(y).get_direction());
-+
-+		if (is_a<infinity>(x)) 
-+			return atan2_eval(ex_to<infinity>(x).get_direction(), 0);
-+		if (is_a<infinity>(y)) 
-+			return atan2_eval(0, ex_to<infinity>(y).get_direction());
-+	}
-+
- 	// atan2(real, real) -> atan(y/x) +/- Pi
- 	if (y.info(info_flags::real) && x.info(info_flags::real)) {
- 		if (x.info(info_flags::positive))
-@@ -1119,37 +1136,6 @@
- 				return atan(y/x)-Pi;
- 		}
- 	}
--
--	// atan(infinity, infinity) -> error
--	// atan(oo, x) -> 0
--	// atan(-oo, x) & x negative -> -Pi
--	// atan(-oo, x) -> Pi
--	// atan(UnsignedInfinity, x) -> error
--	if (y.info(info_flags::infinity)) {
--		if (x.info(info_flags::infinity))
--			throw (std::runtime_error("arctan2_eval(): arctan2(infinity, infinity) encountered"));
--		if (y.is_equal(Infinity)) 
--			return _ex0;
--		if (y.is_equal(NegInfinity)) {
--			if (x.info(info_flags::negative))
--				return _ex_1*Pi;
--			return Pi;
--		}
--		// y is unsigned_infinity
--		throw (std::runtime_error("arctan2_eval(): arctan2(unsigned_infinity, x) encountered"));
--	}
--
--	// atan(x, oo) -> Pi/2
--	// atan(x, -oo) -> -Pi/2
--	// atan(x, UnsignedInfinity) -> error
--	if (x.info(info_flags::infinity)) {
--		if (x.is_equal(Infinity))
--			return _ex1_2*Pi;
--		if (x.is_equal(NegInfinity))
--			return _ex_1_2*Pi;
--		// x is unsigned_infinity
--		throw (std::runtime_error("arctan2_eval(): arctan2(x, unsigned_infinity) encountered"));
--	}
- 		
- 	return atan2(y, x).hold();
- }    
 diff --git a/ginac/mul.cpp b/ginac/mul.cpp
 --- a/ginac/mul.cpp
 +++ b/ginac/mul.cpp
  	exvector neg_powers, others;
  	while (it != itend) {
  		GINAC_ASSERT(is_exactly_a<numeric>(it->coeff));
-@@ -653,8 +652,10 @@
- 	} else if (seq_size==0) {
- 		// *(;c) -> c
- 		return overall_coeff;
--	} else if (seq_size==1 && overall_coeff.is_equal(_ex1)) {
-+	} else if (seq_size==1 && overall_coeff.is_equal(_ex1) &&
-+		   !ex_to<numeric>(overall_coeff).is_parent_pos_char()) {
- 		// *(x;1) -> x
-+		// except in positive characteristic: 1*(x+2) = x in F_2
- 		return recombine_pair_to_ex(*(seq.begin()));
- 	} else if ((seq_size==1) &&
- 	           is_exactly_a<add>((*seq.begin()).rest) &&
-@@ -787,10 +788,10 @@
- 	infinity result = ex_to<infinity>(recombine_pair_to_ex(*infinity_iter));
- 	result *= overall_coeff;
- 
--        for (epvector::const_iterator i = seq.begin(); i != seq.end(); i++) {
--                if (i == infinity_iter) continue;
-+	for (epvector::const_iterator i = seq.begin(); i != seq.end(); i++) {
-+		if (i == infinity_iter) continue;
- 		result *= recombine_pair_to_ex(*i);
--        }
-+	}
- 	return result;
- }
- 
 @@ -1507,15 +1508,15 @@
  	}
  }
  	bool operator() (const expair &lh, const expair &rh) const;
  };
  
-diff --git a/ginac/power.cpp b/ginac/power.cpp
---- a/ginac/power.cpp
-+++ b/ginac/power.cpp
-@@ -476,10 +476,10 @@
- 		if (eexponent.info(info_flags::negative))
- 			return _ex0;
- 		if (eexponent.info(info_flags::positive))
--			if (basis_inf.is_plus_infinity())
--				return Infinity;
-+			if (basis_inf.is_unsigned_infinity())
-+				return UnsignedInfinity;
- 			else
--				return UnsignedInfinity;
-+				return mul(pow(basis_inf.get_direction(), eexponent), Infinity);
- 		throw(std::domain_error("power::eval(): pow(Infinity, c)"
- 					" for constant of undetermined sign is not defined."));
- 	}
-@@ -493,7 +493,11 @@
- 			throw(std::domain_error("power::eval(): pow(f(x), infinity) is not defined."));
- 		// x^(c*oo) --> (x^c)^(+oo)
- 		const ex abs_base = abs(pow(ebasis, exp_inf.get_direction()));
--		if (abs_base > _ex1) return Infinity;
-+		if (abs_base > _ex1) 
-+			if (ebasis.info(info_flags::positive))
-+				return Infinity;
-+			else
-+				return UnsignedInfinity;
- 		if (abs_base < _ex1) return _ex0;
- 		if (abs_base == _ex1)
- 			throw(std::domain_error("power::eval(): pow(1, Infinity) is not defined."));