package org.matheclipse.core.reflection.system;

import static org.matheclipse.core.expression.F.$s;
import static org.matheclipse.core.expression.F.Binomial;
import static org.matheclipse.core.expression.F.C0;
import static org.matheclipse.core.expression.F.C1;
import static org.matheclipse.core.expression.F.C1D2;
import static org.matheclipse.core.expression.F.C2;
import static org.matheclipse.core.expression.F.CN1;
import static org.matheclipse.core.expression.F.Cos;
import static org.matheclipse.core.expression.F.List;
import static org.matheclipse.core.expression.F.Plus;
import static org.matheclipse.core.expression.F.Power;
import static org.matheclipse.core.expression.F.Sin;
import static org.matheclipse.core.expression.F.Sum;
import static org.matheclipse.core.expression.F.Times;
import static org.matheclipse.core.expression.F.evalExpandAll;

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.IInteger;
import org.matheclipse.core.interfaces.ISymbol;

/**
 * Expands the argument of sine and cosine functions.
 * 
 * List
 * of trigonometric identities
 */
public class TrigExpand implements IFunctionEvaluator {
	public TrigExpand() {
	}

	public IExpr evaluate(final IAST ast) {
		Validate.checkSize(ast, 2);

		IExpr temp = ast.arg1();
		IExpr result = temp;
		while (temp != null) {
			result = evalExpandAll(temp);
			temp = null;
			if (result.isAST() && ((IAST) result).size() == 2) {
				if (result.getAt(1).isPlus()) {
					if (result.isSin()) {
						temp = expandSinPlus((IAST) result.getAt(1), 1);
					} else if (result.isCos()) {
						temp = expandCosPlus((IAST) result.getAt(1), 1);
					}
				} else if (result.getAt(1).isTimes()) {
					IAST timesAST = (IAST) result.getAt(1);
					if (timesAST.arg1().isInteger()) {
						IInteger iNum = (IInteger) timesAST.arg1();
						if (iNum.isGreaterThan(C0)) {
							IAST rest = F.Times();
							rest.addAll(timesAST, 2, timesAST.size());
							if (result.isSin()) {
								return Sum(Times(Times(Times(Power(CN1, Times(Plus(F.$s("i"), Times(CN1, C1)), C1D2)), Binomial(iNum, $s("i"))),
										Power(Cos(rest), Plus(iNum, Times(CN1, $s("i"))))), Power(Sin(rest), $s("i"))), List($s("i"), C1, iNum, C2));
							} else if (result.isCos()) {
								return Sum(Times(Times(Times(Power(CN1, Times(F.$s("i"), C1D2)), Binomial(iNum, $s("i"))), Power(Cos(rest), Plus(
										iNum, Times(CN1, $s("i"))))), Power(Sin(rest), $s("i"))), List($s("i"), C0, iNum, C2));
							}
						}
					}
				}
			}
			if (temp != null) {
				result = temp;
			}
		}
		return result;
	}

	private IExpr expandSinPlus(IAST plusAST, int startPosition) {
		if (startPosition > plusAST.size() - 2) {
			return null;
		}
		IAST result = Plus();
		if (startPosition == plusAST.size() - 2) {
			result.add(Times(Sin(plusAST.get(startPosition)), Cos(plusAST.get(startPosition + 1))));
			result.add(Times(Cos(plusAST.get(startPosition)), Sin(plusAST.get(startPosition + 1))));
		} else {
			result.add(Times(Sin(plusAST.get(startPosition)), expandCosPlus(plusAST, startPosition + 1)));
			result.add(Times(Cos(plusAST.get(startPosition)), expandSinPlus(plusAST, startPosition + 1)));
		}
		return result;
	}

	private IExpr expandCosPlus(IAST plusAST, int startPosition) {
		if (startPosition > plusAST.size() - 2) {
			return null;
		}
		IAST result = Plus();
		if (startPosition == plusAST.size() - 2) {
			result.add(Times(Cos(plusAST.get(startPosition)), Cos(plusAST.get(startPosition + 1))));
			result.add(Times(CN1, Sin(plusAST.get(startPosition)), Sin(plusAST.get(startPosition + 1))));
		} else {
			result.add(Times(Cos(plusAST.get(startPosition)), expandCosPlus(plusAST, startPosition + 1)));
			result.add(Times(CN1, Sin(plusAST.get(startPosition)), expandSinPlus(plusAST, startPosition + 1)));
		}
		return result;
	}

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

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

}

 

Ads help maintain this website.