package org.matheclipse.core.reflection.system;

import static org.matheclipse.core.expression.F.$;
import static org.matheclipse.core.expression.F.C2;
import static org.matheclipse.core.expression.F.CI;
import static org.matheclipse.core.expression.F.CN1;
import static org.matheclipse.core.expression.F.Abs;
import static org.matheclipse.core.expression.F.Cos;
import static org.matheclipse.core.expression.F.Cosh;
import static org.matheclipse.core.expression.F.Cot;
import static org.matheclipse.core.expression.F.Csc;
import static org.matheclipse.core.expression.F.Im;
import static org.matheclipse.core.expression.F.Plus;
import static org.matheclipse.core.expression.F.Power;
import static org.matheclipse.core.expression.F.Re;
import static org.matheclipse.core.expression.F.Sec;
import static org.matheclipse.core.expression.F.Sin;
import static org.matheclipse.core.expression.F.Sinh;
import static org.matheclipse.core.expression.F.Sqrt;
import static org.matheclipse.core.expression.F.Tan;
import static org.matheclipse.core.expression.F.Times;
import static org.matheclipse.core.expression.F.integer;

import org.matheclipse.core.eval.exception.Validate;
import org.matheclipse.core.eval.interfaces.IFunctionEvaluator;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.ISymbol;
import org.matheclipse.core.visit.VisitorExpr;

/**
 * Exponential definitions for trigonometric functions
 * 
 * See Wikipedia - List of trigonometric identities
 */
public class ComplexExpand implements IFunctionEvaluator {

	public ComplexExpand() {
	}

	static class ComplexExpandVisitor extends VisitorExpr {
		public ComplexExpandVisitor() {
			super();
		}

		@Override
		public IExpr visit2(IExpr head, IExpr arg1) {
			IExpr x = arg1;
			IExpr result = arg1.accept(this);
			if (result != null) {
				x = result;
			}
			IExpr reX = Re(x);
			IExpr imX = Im(x);
			if (x.isSymbol()) {
				if (head.equals(Re)) {
					return x;
				}
				if (head.equals(Im)) {
					return F.C0;
				}
				reX = x;
				imX = F.C0;
			} else {
				reX = F.eval(Re(x));
				imX = F.eval(Im(x));
				IExpr temp = complexExpandNull(reX);
				if (temp != null) {
					reX = temp;
				}
				temp = complexExpandNull(imX);
				if (temp != null) {
					imX = temp;
				}
			}

			if (head.equals(Abs)) {
				// Sqrt[reX^2 + imX^2]
				return complexExpand(Sqrt(Plus(Power(reX, C2), Power(imX, C2))));
			}
			if (head.equals(Cos)) {
				// Cosh[Im[x]]*Cos[Re[x]]+I*Sinh[Im[x]]*Sin[Re[x]]
				return Plus(Times(Cos(reX), Cosh(imX)), Times(CI, Sin(reX), Sinh(imX)));
			}
			if (head.equals(Cot)) {
				// -(Sin[2*Re[x]]/(Cos[2*Re[x]]-Cosh[2*Im[x]]))+(I*Sinh[2*Im[x]])/(Cos[2*Re[x]]-Cosh[2*Im[x]])
				return Plus(
						Times(CN1, Sin(Times(C2, reX)), Power(Plus(Cos(Times(C2, reX)), Times(CN1, Cosh(Times(C2, imX)))), CN1)),
						Times(CI, Sinh(Times(C2, imX)), Power(Plus(Cos(Times(C2, reX)), Times(CN1, Cosh(Times(C2, imX)))), CN1)));
			}
			if (head.equals(Csc)) {
				// (-2 Cosh[Im[x]] Sin[Re[x]])/(Cos[2 Re[x]] - Cosh[2 Im[x]]) + ((2 I) Cos[Re[x]] Sinh[Im[x]])/(Cos[2 Re[x]]-Cosh[2
				// Im[x]])
				return Plus(
						Times(integer(-2L), Cosh(imX), Sin(reX),
								Power(Plus(Cos(Times(C2, reX)), Times(CN1, Cosh(Times(C2, imX)))), CN1)),
						Times(C2, CI, Cos(reX), Sinh(imX), Power(Plus(Cos(Times(C2, reX)), Times(CN1, Cosh(Times(C2, imX)))), CN1)));
			}
			if (head.equals(Sec)) {
				// (2 Cos[Re[x]] Cosh[Im[x]])/(Cos[2 Re[x]] + Cosh[2 Im[x]]) + ((2 I) Sin[Re[x]] Sinh[Im[x]])/(Cos[2 Re[x]] + Cosh[2
				// Im[x]])
				return Plus(Times(C2, Cos(reX), Cosh(imX), Power(Plus(Cos(Times(C2, reX)), Cosh(Times(C2, imX))), CN1)),
						Times(C2, CI, Sin(reX), Sinh(imX), Power(Plus(Cos(Times(C2, reX)), Cosh(Times(C2, imX))), CN1)));
			}
			if (head.equals(Sin)) {
				// Cosh[Im[x]]*Sin[Re[x]]+I*Sinh[Im[x]]*Cos[Re[x]]
				return Plus(Times(Cosh(imX), Sin(reX)), Times(CI, Sinh(imX), Cos(reX)));
			}
			if (head.equals(Tan)) {
				// Sin[2*Re[x]]/(Cos[2*Re[x]] + Cosh[2*Im[x]]) + (I*Sinh[2*Im[x]])/(Cos[2*Re[x]] + Cosh[2*Im[x]])
				return Plus(Times(Sin(Times(C2, reX)), Power(Plus(Cos(Times(C2, reX)), Cosh(Times(C2, imX))), CN1)),
						Times(CI, Sinh(Times(C2, imX)), Power(Plus(Cos(Times(C2, reX)), Cosh(Times(C2, imX))), CN1)));
			}
			if (result != null) {
				return $(head, result);
			}
			return null;
		}
	}

	public IExpr evaluate(final IAST ast) {
		Validate.checkRange(ast, 1, 2);
		IExpr arg1 = ast.arg1();
		return complexExpand(arg1);
	}

	private static IExpr complexExpand(IExpr arg1) {
		IExpr result = complexExpandNull(arg1);
		if (result != null) {
			return result;
		}
		return arg1;
	}

	private static IExpr complexExpandNull(IExpr arg1) {
		ComplexExpandVisitor tteVisitor = new ComplexExpandVisitor();
		return arg1.accept(tteVisitor);
	}

	public IExpr numericEval(final IAST functionList) {
		return evaluate(functionList);
	}

	public void setUp(final ISymbol symbol) {
		symbol.setAttributes(ISymbol.LISTABLE);
	}

}

 

Ads help maintain this website.