+//////////
+// complex conjugate
+//////////
+
+static ex conjugate_evalf(const ex & arg)
+{
+ if (is_exactly_a<numeric>(arg)) {
+ return ex_to<numeric>(arg).conjugate();
+ }
+ return conjugate_function(arg).hold();
+}
+
+static ex conjugate_eval(const ex & arg)
+{
+ return arg.conjugate();
+}
+
+static void conjugate_print_latex(const ex & arg, const print_context & c)
+{
+ c.s << "\\bar{"; arg.print(c); c.s << "}";
+}
+
+static ex conjugate_conjugate(const ex & arg)
+{
+ return arg;
+}
+
+// If x is real then U.diff(x)-I*V.diff(x) represents both conjugate(U+I*V).diff(x)
+// and conjugate((U+I*V).diff(x))
+static ex conjugate_expl_derivative(const ex & arg, const symbol & s)
+{
+ if (s.info(info_flags::real))
+ return conjugate(arg.diff(s));
+ else {
+ exvector vec_arg;
+ vec_arg.push_back(arg);
+ return fderivative(ex_to<function>(conjugate(arg)).get_serial(),0,vec_arg).hold()*arg.diff(s);
+ }
+}
+
+static ex conjugate_real_part(const ex & arg)
+{
+ return arg.real_part();
+}
+
+static ex conjugate_imag_part(const ex & arg)
+{
+ return -arg.imag_part();
+}
+
+static bool func_arg_info(const ex & arg, unsigned inf)
+{
+ // for some functions we can return the info() of its argument
+ // (think of conjugate())
+ 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;
+}
+
+static bool conjugate_info(const ex & arg, unsigned inf)
+{
+ return func_arg_info(arg, inf);
+}
+
+REGISTER_FUNCTION(conjugate_function, eval_func(conjugate_eval).
+ evalf_func(conjugate_evalf).
+ expl_derivative_func(conjugate_expl_derivative).
+ info_func(conjugate_info).
+ print_func<print_latex>(conjugate_print_latex).
+ conjugate_func(conjugate_conjugate).
+ real_part_func(conjugate_real_part).
+ imag_part_func(conjugate_imag_part).
+ set_name("conjugate","conjugate"));
+
+//////////
+// real part
+//////////
+
+static ex real_part_evalf(const ex & arg)
+{
+ if (is_exactly_a<numeric>(arg)) {
+ return ex_to<numeric>(arg).real();
+ }
+ return real_part_function(arg).hold();
+}
+
+static ex real_part_eval(const ex & arg)
+{
+ return arg.real_part();
+}
+
+static void real_part_print_latex(const ex & arg, const print_context & c)
+{
+ c.s << "\\Re"; arg.print(c); c.s << "";
+}
+
+static ex real_part_conjugate(const ex & arg)
+{
+ return real_part_function(arg).hold();
+}
+
+static ex real_part_real_part(const ex & arg)
+{
+ return real_part_function(arg).hold();
+}
+
+static ex real_part_imag_part(const ex & arg)
+{
+ return 0;
+}
+
+// If x is real then Re(e).diff(x) is equal to Re(e.diff(x))
+static ex real_part_expl_derivative(const ex & arg, const symbol & s)
+{
+ if (s.info(info_flags::real))
+ return real_part_function(arg.diff(s));
+ else {
+ exvector vec_arg;
+ vec_arg.push_back(arg);
+ return fderivative(ex_to<function>(real_part(arg)).get_serial(),0,vec_arg).hold()*arg.diff(s);
+ }
+}
+
+REGISTER_FUNCTION(real_part_function, eval_func(real_part_eval).
+ evalf_func(real_part_evalf).
+ expl_derivative_func(real_part_expl_derivative).
+ print_func<print_latex>(real_part_print_latex).
+ conjugate_func(real_part_conjugate).
+ real_part_func(real_part_real_part).
+ imag_part_func(real_part_imag_part).
+ set_name("real_part","real_part"));
+
+//////////
+// imag part
+//////////
+
+static ex imag_part_evalf(const ex & arg)
+{
+ if (is_exactly_a<numeric>(arg)) {
+ return ex_to<numeric>(arg).imag();
+ }
+ return imag_part_function(arg).hold();
+}
+
+static ex imag_part_eval(const ex & arg)
+{
+ return arg.imag_part();
+}
+
+static void imag_part_print_latex(const ex & arg, const print_context & c)
+{
+ c.s << "\\Im"; arg.print(c); c.s << "";
+}
+
+static ex imag_part_conjugate(const ex & arg)
+{
+ return imag_part_function(arg).hold();
+}
+
+static ex imag_part_real_part(const ex & arg)
+{
+ return imag_part_function(arg).hold();
+}
+
+static ex imag_part_imag_part(const ex & arg)
+{
+ return 0;
+}
+
+// If x is real then Im(e).diff(x) is equal to Im(e.diff(x))
+static ex imag_part_expl_derivative(const ex & arg, const symbol & s)
+{
+ if (s.info(info_flags::real))
+ return imag_part_function(arg.diff(s));
+ else {
+ exvector vec_arg;
+ vec_arg.push_back(arg);
+ return fderivative(ex_to<function>(imag_part(arg)).get_serial(),0,vec_arg).hold()*arg.diff(s);
+ }
+}
+
+REGISTER_FUNCTION(imag_part_function, eval_func(imag_part_eval).
+ evalf_func(imag_part_evalf).
+ expl_derivative_func(imag_part_expl_derivative).
+ print_func<print_latex>(imag_part_print_latex).
+ conjugate_func(imag_part_conjugate).
+ real_part_func(imag_part_real_part).
+ imag_part_func(imag_part_imag_part).
+ set_name("imag_part","imag_part"));
+