From 4c5ebec6ca4e49d88f83864e2d6f43345d0f0575 Mon Sep 17 00:00:00 2001
From: "Vladimir V. Kisil" <kisilv@maths.leeds.ac.uk>
Date: Fri, 2 Aug 2013 11:05:21 +0100
Subject: [PATCH 9/9] Function can report info (preliminary).

Signed-off-by: Vladimir V. Kisil <kisilv@maths.leeds.ac.uk>
---
 check/exam_inifcns.cpp |    9 ++++++++
 ginac/flags.h          |    4 ++--
 ginac/function.cppy    |   27 ++++++++++++++++++++++
 ginac/function.hppy    |    6 +++++
 ginac/function.py      |    2 +-
 ginac/inifcns.cpp      |   60 ++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 105 insertions(+), 3 deletions(-)

diff --git a/check/exam_inifcns.cpp b/check/exam_inifcns.cpp
index 12a6c02..a62fe44 100644
--- a/check/exam_inifcns.cpp
+++ b/check/exam_inifcns.cpp
@@ -253,6 +253,15 @@ static unsigned inifcns_consist_abs()
 	if (!abs(step(z)).eval().is_equal(step(z)))
 		++result;
 
+	if (!abs(p).info(info_flags::positive) || !abs(a).info(info_flags::real))
+		++result;
+
+	if (abs(a).info(info_flags::positive) || !abs(a).info(info_flags::real))
+		++result;
+
+	if (abs(z).info(info_flags::positive) || !abs(z).info(info_flags::real))
+		++result;
+
 	return result;
 }
 
diff --git a/ginac/flags.h b/ginac/flags.h
index f4f0f6b..cfb75d0 100644
--- a/ginac/flags.h
+++ b/ginac/flags.h
@@ -196,7 +196,7 @@ public:
 		hash_calculated = 0x0008, ///< .calchash() has already done its job
 		not_shareable   = 0x0010, ///< don't share instances of this object between different expressions unless explicitly asked to (used by ex::compare())
 		has_indices	= 0x0020,
-		has_no_indices	= 0x0040  // ! (has_indices || has_no_indices) means "don't know"
+		has_no_indices	= 0x0040,  // ! (has_indices || has_no_indices) means "don't know"
 		is_positive	= 0x0080,
 		is_negative	= 0x0100,
 		purely_indefinite = 0x0200,  // If set in a mul, then it does not contains any terms with determined signs, used in power::expand()
@@ -207,7 +207,7 @@ public:
 class info_flags {
 public:
 	enum {
-		// answered by class numeric, add, mul and symbols/constants in particular domains
+		// answered by class numeric, add, mul, function and symbols/constants in particular domains
 		numeric,
 		real,
 		rational,
diff --git a/ginac/function.cppy b/ginac/function.cppy
index 1b76184..89fb369 100644
--- a/ginac/function.cppy
+++ b/ginac/function.cppy
@@ -80,6 +80,7 @@ void function_options::initialize()
 	nparams = 0;
 	eval_f = evalf_f = real_part_f = imag_part_f = conjugate_f = expand_f
 		= derivative_f = power_f = series_f = 0;
+	info_f = 0;
 	evalf_params_first = true;
 	use_return_type = false;
 	eval_use_exvector_args = false;
@@ -92,6 +93,7 @@ void function_options::initialize()
 	power_use_exvector_args = false;
 	series_use_exvector_args = false;
 	print_use_exvector_args = false;
+	info_use_exvector_args = false;
 	use_remember = false;
 	functions_with_same_name = 1;
 	symtree = 0;
@@ -594,6 +596,31 @@ ex function::imag_part() const
 	throw(std::logic_error("function::imag_part(): invalid nparams"));
 }
 
+/** Implementation of ex::info for functions. */
+bool function::info(unsigned inf) const
+{
+	GINAC_ASSERT(serial<registered_functions().size());
+	const function_options & opt = registered_functions()[serial];
+
+	if (opt.info_f==0) {
+		return basic::info(inf);
+	}
+
+	if (opt.info_use_exvector_args) {
+		return ((info_funcp_exvector)(opt.info_f))(seq, inf);
+	}
+
+	switch (opt.nparams) {
+		// the following lines have been generated for max. @maxargs@ parameters
++++ for N in range(1, maxargs + 1):
+		case @N@:
+			return ((info_funcp_@N@)(opt.info_f))(@seq('seq[%(n)d]', N, 0)@, inf);
+---
+		// end of generated lines
+	}
+	throw(std::logic_error("function::info(): invalid nparams"));
+}
+
 // protected
 
 /** Implementation of ex::diff() for functions. It applies the chain rule,
diff --git a/ginac/function.hppy b/ginac/function.hppy
index fa17813..5d7ca09 100644
--- a/ginac/function.hppy
+++ b/ginac/function.hppy
@@ -62,6 +62,7 @@ typedef ex (* derivative_funcp)();
 typedef ex (* power_funcp)();
 typedef ex (* series_funcp)();
 typedef void (* print_funcp)();
+typedef bool (* info_funcp)();
 
 // the following lines have been generated for max. @maxargs@ parameters
 +++ for N, args in [ ( N, seq('const ex &', N) ) for N in range(1, maxargs + 1) ]:
@@ -75,6 +76,7 @@ typedef ex (* derivative_funcp_@N@)( @args@, unsigned );
 typedef ex (* power_funcp_@N@)( @args@, const ex & );
 typedef ex (* series_funcp_@N@)( @args@, const relational &, int, unsigned );
 typedef void (* print_funcp_@N@)( @args@, const print_context & );
+typedef bool (* info_funcp_@N@)( @args@, unsigned );
 ---
 // end of generated lines
 
@@ -88,6 +90,7 @@ typedef ex (* derivative_funcp_exvector)(const exvector &, unsigned);
 typedef ex (* power_funcp_exvector)(const exvector &, const ex &);
 typedef ex (* series_funcp_exvector)(const exvector &, const relational &, int, unsigned);
 typedef void (* print_funcp_exvector)(const exvector &, const print_context &);
+typedef bool (* info_funcp_exvector)(const exvector &, unsigned);
 
 
 class function_options
@@ -159,6 +162,7 @@ protected:
 	power_funcp power_f;
 	series_funcp series_f;
 	std::vector<print_funcp> print_dispatch_table;
+	info_funcp info_f;
 
 	bool evalf_params_first;
 
@@ -181,6 +185,7 @@ protected:
 	bool power_use_exvector_args;
 	bool series_use_exvector_args;
 	bool print_use_exvector_args;
+	bool info_use_exvector_args;
 
 	unsigned functions_with_same_name;
 
@@ -232,6 +237,7 @@ public:
 	ex imag_part() const;
 	void archive(archive_node& n) const;
 	void read_archive(const archive_node& n, lst& syms);
+	bool info(unsigned inf) const;
 protected:
 	ex derivative(const symbol & s) const;
 	bool is_equal_same_type(const basic & other) const;
diff --git a/ginac/function.py b/ginac/function.py
index 0ecb918..3f5e54e 100755
--- a/ginac/function.py
+++ b/ginac/function.py
@@ -2,7 +2,7 @@
 # encoding: utf-8
 
 maxargs = 14
-methods = "eval evalf conjugate real_part imag_part expand derivative power series print".split()
+methods = "eval evalf conjugate real_part imag_part expand derivative power series info print".split()
 
 import sys, os, optparse
 sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'scripts'))
diff --git a/ginac/inifcns.cpp b/ginac/inifcns.cpp
index 168102b..2bcccd8 100644
--- a/ginac/inifcns.cpp
+++ b/ginac/inifcns.cpp
@@ -76,8 +76,40 @@ static ex conjugate_imag_part(const ex & arg)
 	return -arg.imag_part();
 }
 
+bool conjugate_info(const ex & arg, unsigned inf)
+{
+	switch (inf) {
+		case info_flags::polynomial:
+		case info_flags::integer_polynomial:
+		case info_flags::cinteger_polynomial:
+		case info_flags::rational_polynomial:
+		case info_flags::real:
+		case info_flags::rational:
+		case info_flags::integer:
+		case info_flags::crational:
+		case info_flags::cinteger:
+		case info_flags::even:
+		case info_flags::odd:
+		case info_flags::prime:
+		case info_flags::crational_polynomial:
+		case info_flags::rational_function: 
+		case info_flags::algebraic:
+		case info_flags::positive:
+		case info_flags::negative:
+		case info_flags::nonnegative:
+		case info_flags::posint:
+		case info_flags::negint:
+		case info_flags::nonnegint:
+		case info_flags::has_indices:
+			return arg.info(inf);
+	}
+	return false;
+}
+
+
 REGISTER_FUNCTION(conjugate_function, eval_func(conjugate_eval).
                                       evalf_func(conjugate_evalf).
+                                      info_func(conjugate_info).
                                       print_func<print_latex>(conjugate_print_latex).
                                       conjugate_func(conjugate_conjugate).
                                       real_part_func(conjugate_real_part).
@@ -266,9 +298,37 @@ static ex abs_power(const ex & arg, const ex & exp)
 		return power(abs(arg), exp).hold();
 }
 
+bool abs_info(const ex & arg, unsigned inf)
+{
+	switch (inf) {
+		case info_flags::integer:
+		case info_flags::even:
+		case info_flags::odd:
+		case info_flags::prime:
+			return arg.info(inf);
+		case info_flags::nonnegint:
+			return arg.info(info_flags::integer);
+		case info_flags::nonnegative:
+		case info_flags::real:
+			return true;
+		case info_flags::negative:
+			return false;
+		case info_flags::positive:
+			return arg.info(info_flags::positive) ||  arg.info(info_flags::negative);
+		case info_flags::has_indices: {
+			if (arg.info(info_flags::has_indices))
+				return true;
+			else
+				return false;
+		}
+	}
+	return false;
+}
+
 REGISTER_FUNCTION(abs, eval_func(abs_eval).
                        evalf_func(abs_evalf).
                        expand_func(abs_expand).
+                       info_func(abs_info).
                        print_func<print_latex>(abs_print_latex).
                        print_func<print_csrc_float>(abs_print_csrc_float).
                        print_func<print_csrc_double>(abs_print_csrc_float).
-- 
1.7.10.4

