package org.matheclipse.core.reflection.system;

import static org.matheclipse.core.expression.F.$p;
import static org.matheclipse.core.expression.F.$s;
import static org.matheclipse.core.expression.F.C0;
import static org.matheclipse.core.expression.F.C1;
import static org.matheclipse.core.expression.F.CI;
import static org.matheclipse.core.expression.F.CN1;
import static org.matheclipse.core.expression.F.Condition;
import static org.matheclipse.core.expression.F.Cos;
import static org.matheclipse.core.expression.F.Cot;
import static org.matheclipse.core.expression.F.Csc;
import static org.matheclipse.core.expression.F.E;
import static org.matheclipse.core.expression.F.Less;
import static org.matheclipse.core.expression.F.List;
import static org.matheclipse.core.expression.F.Log;
import static org.matheclipse.core.expression.F.Pi;
import static org.matheclipse.core.expression.F.Power;
import static org.matheclipse.core.expression.F.Sec;
import static org.matheclipse.core.expression.F.Set;
import static org.matheclipse.core.expression.F.SetDelayed;
import static org.matheclipse.core.expression.F.Sin;
import static org.matheclipse.core.expression.F.Tan;
import static org.matheclipse.core.expression.F.Times;
import static org.matheclipse.core.expression.F.fraction;

import java.math.BigInteger;

import org.apache.commons.math3.fraction.BigFraction;
import org.matheclipse.core.eval.EvalEngine;
import org.matheclipse.core.eval.interfaces.AbstractArg2;
import org.matheclipse.core.eval.interfaces.INumeric;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.expression.NumberUtil;
import org.matheclipse.core.generic.Functors;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IComplex;
import org.matheclipse.core.interfaces.IComplexNum;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.IFraction;
import org.matheclipse.core.interfaces.IInteger;
import org.matheclipse.core.interfaces.INum;
import org.matheclipse.core.interfaces.INumber;
import org.matheclipse.core.interfaces.IRational;
import org.matheclipse.core.interfaces.ISignedNumber;
import org.matheclipse.core.interfaces.ISymbol;

public class Power extends AbstractArg2 implements INumeric {
	/**
	 * Constructor for the singleton
	 */
	public final static Power CONST = new Power();
	/**
	 * 
	 * E^(I*Pi)=(-1),
	 *      E^Log[x_]:=x,
	 *      Tan[x_]^(n_IntegerQ):=Cot[x]^(-n)/;(n<0)
	 *      Cot[x_]^(n_IntegerQ):=Tan[x]^(-n)/;(n<0),
	 *      Sec[x_]^(n_IntegerQ):=Cos[x]^(-n)/;(n<0),
	 *      Cos[x_]^(n_IntegerQ):=Sec[x]^(-n)/;(n<0),
	 *      Csc[x_]^(n_IntegerQ):=Sin[x]^(-n)/;(n<0),
	 *      Sin[x_]^(n_IntegerQ):=Csc[x]^(-n)/;(n<0),
	 * 
*/ final static IAST RULES = List( Set(Power(E, Times(CI, Pi)), CN1), SetDelayed(Power(E, Log($p("x"))), $s("x")), SetDelayed(Power(Tan($p("x")), $p("n", $s("IntegerQ"))), Condition(Power(Cot($s("x")), Times(CN1, $s("n"))), Less($s("n"), C0))), SetDelayed(Power(Cot($p("x")), $p("n", $s("IntegerQ"))), Condition(Power(Tan($s("x")), Times(CN1, $s("n"))), Less($s("n"), C0))), SetDelayed(Power(Sec($p("x")), $p("n", $s("IntegerQ"))), Condition(Power(Cos($s("x")), Times(CN1, $s("n"))), Less($s("n"), C0))), SetDelayed(Power(Cos($p("x")), $p("n", $s("IntegerQ"))), Condition(Power(Sec($s("x")), Times(CN1, $s("n"))), Less($s("n"), C0))), SetDelayed(Power(Csc($p("x")), $p("n", $s("IntegerQ"))), Condition(Power(Sin($s("x")), Times(CN1, $s("n"))), Less($s("n"), C0))), SetDelayed(Power(Sin($p("x")), $p("n", $s("IntegerQ"))), Condition(Power(Csc($s("x")), Times(CN1, $s("n"))), Less($s("n"), C0)))); @Override public IAST getRuleAST() { return RULES; } public Power() { } // public IExpr e2DblComArg(IDoubleComplex d0, IDoubleComplex d1, // AbstractExpressionFactory factory) { // return d0.pow(d1); // } @Override public IExpr e2DblComArg(final IComplexNum c0, final IComplexNum c1) { return c0.pow(c1); } @Override public IExpr e2ComArg(final IComplex c0, final IComplex c1) { return null; } @Override public IExpr e2DblArg(final INum d0, final INum d1) { if (d1.isMinusOne()) { return d0.inverse(); } if (d1.isNumIntValue()) { return d0.pow(d1); } if (d0.isNegative()) { return F.complexNum(d0.doubleValue()).pow(F.complexNum(d1.doubleValue())); } return d0.pow(d1); } @Override public IExpr e2IntArg(final IInteger i0, final IInteger i1) { if (i0.equals(F.C0)) { // all other cases see e2ObjArg return null; } if (i1.isNegative()) { return F.fraction(F.C1, i0.pow(((IInteger) i1.negate()).getBigNumerator().intValue())); } return i0.pow(i1.getBigNumerator().intValue()); } @Override public IExpr e2ObjArg(final IExpr o0, final IExpr o1) { if (o0.equals(F.Indeterminate) || o1.equals(F.Indeterminate)) { return F.Indeterminate; } if (o0.isZero()) { EvalEngine ee = EvalEngine.get(); if (o1.isZero()) { // 0^0 // TODO add a real log message // throw new DivisionByZero("0^0"); if (!ee.isQuietMode()) { ee.getOutPrintStream().println("Infinite expression 0^0"); } return F.Indeterminate; } if ((o1.isSignedNumber()) && ((ISignedNumber) o1).isNegative()) { if (!ee.isQuietMode()) { ee.getOutPrintStream().println("Infinite expression 0^(negative number)"); } return F.CComplexInfinity; } return F.C0; } if (o1.isZero()) { return F.C1; } if (o1.isOne()) { return o0; } if (o0.isOne()) { return F.C1; } if (o1.isSignedNumber()) { ISignedNumber is = (ISignedNumber) o1; if (o0.isInfinity()) { if (is.isNegative()) { return F.C0; } else { return F.CInfinity; } } else if (o0.isNegativeInfinity() && o1.isInteger()) { IInteger ii = (IInteger) o1; if (ii.isNegative()) { return F.C0; } else { if (ii.isOdd()) { return F.CNInfinity; } else { return F.CInfinity; } } } } if (o1.isMinusOne()) { if (o0.isNumber()) { return ((INumber) o0).inverse(); } } if (o0.isSignedNumber() && ((ISignedNumber) o0).isNegative() && o1.equals(F.C1D2)) { // extract I for sqrt return F.Times(F.CI, F.Power(F.Times(F.CN1, o0), o1)); } if (o0.isAST()) { IAST arg0 = (IAST) o0; if (arg0.isTimes()) { if (o1.isInteger()) { // (a * b * c)^n => a^n * b^n * c^n return arg0.map(Functors.replace1st(Power(F.Null, o1))); } if (o1.isNumber()) { final IAST f0 = arg0; if ((f0.size() > 1) && (f0.arg1().isNumber())) { return Times(Power(f0.arg1(), o1), Power(F.ast(f0, F.Times, true, 2, f0.size()), o1)); } } } if (arg0.isPower()) { if (o1.isInteger()) { // (a ^ b )^n => a ^ (b * n) return F.Power(arg0.arg1(), F.Times(o1, arg0.arg2())); } } } return null; } public IExpr e2FraArg(IFraction f0, IFraction f1) { if (f0.getNumerator().equals(F.C0)) { return F.C0; } if (f1.getNumerator().equals(F.C0)) { return F.C1; } if (f1.equals(F.C1D2)) { if (f0.isNegative()) { return F.Times(F.CI, F.Power(f0.negate(), f1)); } } if (f1.equals(F.CN1D2)) { if (f0.isNegative()) { return F.Times(F.CN1, F.CI, F.Power(f0.negate().inverse(), f1.negate())); } } if (!f1.getDenominator().equals(F.C1)) { IInteger a; IInteger b; IFraction f0Temp = f0; if (f0.sign() < 0) { f0Temp = (IFraction) f0Temp.negate(); } if (f1.isNegative()) { a = f0Temp.getDenominator(); b = f0Temp.getNumerator(); } else { a = f0Temp.getNumerator(); b = f0Temp.getDenominator(); } // example: (-27)^(2/3) or 8^(1/3) if (!f1.getNumerator().equals(F.C1)) { try { int exp = f1.getNumerator().toInt(); if (exp < 0) { exp *= (-1); } a = a.pow(exp); b = b.pow(exp); } catch (ArithmeticException e) { return null; } } final IInteger root = f1.getDenominator(); IInteger[] new_numer = calculateRoot(a, root); IInteger[] new_denom = calculateRoot(b, root); final IFraction new_root = F.fraction(C1, root); if (new_numer != null) { if (new_denom != null) { IRational p0 = null; if (new_denom[1].equals(F.C1)) { p0 = new_numer[1]; } else { p0 = fraction(new_numer[1], new_denom[1]); } if (f0.sign() < 0) { return Times(fraction(new_numer[0], new_denom[0]), Power(p0.negate(), new_root)); } return Times(fraction(new_numer[0], new_denom[0]), Power(p0, new_root)); } else { if (a.equals(C1)) { return null; } IRational p0 = null; if (b.equals(F.C1)) { p0 = new_numer[1]; } else { p0 = fraction(new_numer[1], b); } if (f0.sign() < 0) { return Times(new_numer[0], Power(p0.negate(), new_root)); } return Times(new_numer[0], Power(p0, new_root)); } } else { if (new_denom != null) { if (b.equals(C1)) { return null; } IRational p0 = null; if (new_denom[1].equals(F.C1)) { p0 = a; } else { p0 = F.fraction(a, new_denom[1]); } if (f0.sign() < 0) { return Times(fraction(C1, new_denom[0]), Power(p0.negate(), new_root)); } return Times(fraction(C1, new_denom[0]), Power(p0, new_root)); } } return null; } // now f1 denominator == 1 int iNumer; try { iNumer = f1.getNumerator().toInt(); } catch (ArithmeticException iob) { return null; } return f0.pow(iNumer); } /** * Split this integer into the nth-root (with prime factors less equal 1021) and the "rest factor" * * @return {nth-root, rest factor} or null if the root is not available */ private IInteger[] calculateRoot(IInteger a, IInteger root) { try { IInteger[] result = new IInteger[2]; int n = root.toInt(); if (n > 0) { if (a.equals(F.C1)) { return null; } if (a.equals(F.CN1)) { return null; } result = a.nthRootSplit(n); if (result[1].equals(a)) { // no roots found return null; } return result; } } catch (ArithmeticException e) { } return null; } @Override public IExpr eComIntArg(final IComplex c0, final IInteger i1) { if (c0.isZero()) { return F.C0; } if (i1.isZero()) { return F.C1; } return c0.pow(i1.getBigNumerator().intValue()); } public IExpr eComFraArg(final IComplex c0, final IFraction i1) { if (i1.equals(F.C1D2) && c0.getRealPart().equals(BigFraction.ZERO)) { // square root of pure imaginary number BigFraction im = c0.getImaginaryPart(); boolean negative = false; im = im.divide(BigInteger.valueOf(2L)); if (NumberUtil.isNegative(im)) { im = im.negate(); negative = true; } if (NumberUtil.isPerfectSquare(im)) { IExpr temp = F.Sqrt(F.fraction(im)); if (negative) { // Sqrt(im.negate()) - I * Sqrt(im); return F.Plus(temp, F.Times(F.CNI, temp)); } // Sqrt(im.negate()) + I * Sqrt(im); return F.Plus(temp, F.Times(F.CI, temp)); } } return null; } /** {@inheritDoc} */ @Override public void setUp(final ISymbol symbol) { symbol.setAttributes(ISymbol.LISTABLE | ISymbol.NUMERICFUNCTION); super.setUp(symbol); } public double evalReal(final double[] stack, final int top, final int size) { if (size != 2) { throw new UnsupportedOperationException(); } return Math.pow(stack[top - 1], stack[top]); } }

Ads help maintain this website.