Skip to content

Commit

Permalink
WIP #851 refactorings
Browse files Browse the repository at this point in the history
- new @FunctionalInterface Function4 represents a function with 4 args.
- extracted PowerTimesFunction to determine pattern x^n_ * f_(m_*x)
  • Loading branch information
axkr committed Nov 7, 2023
1 parent bae54db commit 90605ac
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 63 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.matheclipse.core.generic;

import org.matheclipse.core.eval.EvalEngine;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.expression.S;
import org.matheclipse.core.interfaces.Function4;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IASTAppendable;
import org.matheclipse.core.interfaces.IExpr;

/**
* Analyze if a {@link S#Times} expression <code>factor1 * factor2</code> is of the form
* <code>x^n_ * f_(m_*x)</code>. If <code>true</code> call the defined <code>function</code>.
*/
public class PowerTimesFunction {
Function4<IAST, IExpr, IExpr, IExpr, IExpr> function;

/**
* Define the function which should be called, if the form <code>x^n_ * f_(m_*x)</code> was found.
*
* @param function <code>function(f,x,n,m)</code>
* @see #xPowNTimesFmx(IExpr, IExpr, IExpr, EvalEngine)
*/
public PowerTimesFunction(Function4<IAST, IExpr, IExpr, IExpr, IExpr> function) {
this.function = function;
}

/**
* Analyze if <code>factor1 * factor2</code> is of the form <code>x^n_ * f_(m_*x)</code>. If
* <code>true</code> call {@link #function}.
*
* @param factor1
* @param factor2
* @param x
*
* @return {@link F#NIL} if the expression is not of the form.
*/
public IExpr xPowNTimesFmx(IExpr factor1, IExpr factor2, final IExpr x, EvalEngine engine) {
IExpr n = F.NIL;
if (factor1.equals(x)) {
n = F.C1;
} else if (factor2.equals(x)) {
n = F.C1;
IExpr temp = factor2;
factor2 = factor1;
factor1 = temp;
}
if (n.isNIL()) {
if (factor1.isPower() && factor1.base().equals(x)
&& (factor1.exponent().isInteger() || factor1.exponent().isVariable())) {
if (!factor1.exponent().equals(x)) {
n = factor1.exponent();
}
} else if (factor2.isPower() && factor2.base().equals(x)
&& (factor2.exponent().isInteger() || factor2.exponent().isVariable())) {
if (!factor2.exponent().equals(x)) {
n = factor2.exponent();
IExpr temp = factor2;
factor2 = factor1;
factor1 = temp;
}
}
}
if (n.isPresent() && factor2.isAST1()) {
IExpr m = F.NIL;
IExpr t2Arg1 = factor2.first();
if (t2Arg1.equals(x)) {
m = F.C1;
} else if (t2Arg1.isTimes()) {
IAST timesAST = (IAST) t2Arg1;
IASTAppendable[] filter = timesAST.filter(arg -> arg.equals(x));
if (filter[0].argSize() == 1) {
IExpr rest = engine.evaluate(filter[1]);
if (rest.isFree(x)) {
m = rest;
}
}
}
if (m.isPresent()) {
IExpr temp = function.apply((IAST) factor2, x, n, m);
if (temp.isPresent()) {
return engine.evaluate(temp);
}
}
}
return F.NIL;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.IInteger;
import org.matheclipse.core.interfaces.ISymbol;
import org.matheclipse.core.patternmatching.Matcher;
import org.matheclipse.core.patternmatching.RulesData;
import org.matheclipse.core.reflection.system.rules.IntegratePowerTimesFunctionRules;
import com.google.common.cache.CacheBuilder;

/**
Expand Down Expand Up @@ -88,6 +90,26 @@ public class Integrate extends AbstractFunctionEvaluator {

private static final CountDownLatch COUNT_DOWN_LATCH = new CountDownLatch(1);

/**
* Define rules for functions of the form <code>Integrate(x^n * unaryFunction(m*x), x)</code>.
*/
private static Matcher POWER_TIMES_FUNCION_MATCHER;

private static Matcher initPowerTimesFunction() {
Matcher MATCHER = new Matcher();
IAST list = IntegratePowerTimesFunctionRules.RULES;

for (int i = 1; i < list.size(); i++) {
IExpr arg = list.get(i);
if (arg.isAST(S.SetDelayed, 3)) {
MATCHER.caseOf(arg.first(), arg.second());
} else if (arg.isAST(S.Set, 3)) {
MATCHER.caseOf(arg.first(), arg.second());
}
}
return MATCHER;
}

/**
* Try to integrate functions of the form <code>x^n * f(m*x)</code>.
*/
Expand Down Expand Up @@ -172,6 +194,9 @@ public void run() {
F.ISet(UtilityFunctionCtors.FractionalPowerQ, //
F.Function(F.And(F.SameQ(F.Head(F.Slot1), S.Power),
F.SameQ(F.Head(F.Part(F.Slot1, F.C2)), S.Rational))));

POWER_TIMES_FUNCION_MATCHER = initPowerTimesFunction();

COUNT_DOWN_LATCH.countDown();
}
}
Expand Down Expand Up @@ -413,68 +438,7 @@ private static IExpr integrateXPowNTimesFMTimesX(IAST unaryFunction, final IExpr
IExpr m) {
int headID = unaryFunction.headID();
if (headID > ID.UNKNOWN) {
switch (headID) {
case ID.ArcCos:
// (x^(1+n)*((2+n)*ArcCos(m*x)+m*x*Hypergeometric2F1(1/2,1+n/2,2+n/2,m^2*x^2)))/((1+n)*(
// 2+n))
return F.Times(F.Power(F.Times(F.Plus(F.C1, n), F.Plus(F.C2, n)), F.CN1),
F.Power(x, F.Plus(F.C1, n)),
F.Plus(F.Times(F.Plus(F.C2, n), F.ArcCos(F.Times(m, x))),
F.Times(m, x, F.Hypergeometric2F1(F.C1D2, F.Plus(F.C1, F.Times(F.C1D2, n)),
F.Plus(F.C2, F.Times(F.C1D2, n)), F.Times(F.Sqr(m), F.Sqr(x))))));
case ID.ArcCosh:
// (x^(1+n)*(ArcCosh(m*x)+(-m*x*Sqrt(1-m^2*x^2)*Hypergeometric2F1(1/2,1+n/2,2+n/2,m^2*x^2))/((2+n)*Sqrt(-1+m*x)*Sqrt(1+m*x))))/(1+n)
return F.Times(F.Power(F.Plus(F.C1, n), F.CN1), F.Power(x, F.Plus(F.C1, n)),
F.Plus(F.ArcCosh(F.Times(m, x)),
F.Times(F.CN1, m, x, F.Sqrt(F.Plus(F.C1, F.Times(F.CN1, F.Sqr(m), F.Sqr(x)))),
F.Power(F.Times(F.Plus(F.C2, n), F.Sqrt(F.Plus(F.CN1, F.Times(m, x))),
F.Sqrt(F.Plus(F.C1, F.Times(m, x)))), F.CN1),
F.Hypergeometric2F1(F.C1D2, F.Plus(F.C1, F.Times(F.C1D2, n)),
F.Plus(F.C2, F.Times(F.C1D2, n)), F.Times(F.Sqr(m), F.Sqr(x))))));

case ID.ArcCot:
// (x^(1+n)*((2+n)*ArcCot(m*x)+m*x*Hypergeometric2F1(1,1+n/2,2+n/2,-m^2*x^2)))/((1+n)*(2+n))
return F.Times(F.Power(F.Times(F.Plus(F.C1, n), F.Plus(F.C2, n)), F.CN1),
F.Power(x, F.Plus(F.C1, n)),
F.Plus(F.Times(F.Plus(F.C2, n), F.ArcCot(F.Times(m, x))),
F.Times(m, x, F.Hypergeometric2F1(F.C1, F.Plus(F.C1, F.Times(F.C1D2, n)),
F.Plus(F.C2, F.Times(F.C1D2, n)), F.Times(F.CN1, F.Sqr(m), F.Sqr(x))))));
case ID.ArcCoth:
// (x^(1+n)*((2+n)*ArcCoth(m*x)-m*x*Hypergeometric2F1(1,1+n/2,2+n/2,m^2*x^2)))/((1+n)*(2+n))
return F.Times(F.Power(F.Times(F.Plus(F.C1, n), F.Plus(F.C2, n)), F.CN1),
F.Power(x, F.Plus(F.C1, n)),
F.Plus(F.Times(F.Plus(F.C2, n), F.ArcCoth(F.Times(m, x))),
F.Times(F.CN1, m, x, F.Hypergeometric2F1(F.C1, F.Plus(F.C1, F.Times(F.C1D2, n)),
F.Plus(F.C2, F.Times(F.C1D2, n)), F.Times(F.Sqr(m), F.Sqr(x))))));
case ID.ArcSin:
// (x^(1+n)*((2+n)*ArcSin[m*x]-m*x*Hypergeometric2F1[1/2,1+n/2,2+n/2,m^2*x^2]))/((1+n)*(2+n))
return F.Times(F.Power(F.Times(F.Plus(F.C1, n), F.Plus(F.C2, n)), F.CN1),
F.Power(x, F.Plus(F.C1, n)),
F.Plus(F.Times(F.Plus(F.C2, n), F.ArcSin(F.Times(m, x))),
F.Times(F.CN1, m, x, F.Hypergeometric2F1(F.C1D2, F.Plus(F.C1, F.Times(F.C1D2, n)),
F.Plus(F.C2, F.Times(F.C1D2, n)), F.Times(F.Sqr(m), F.Sqr(x))))));
case ID.ArcSinh:
// (x^(1+n)*((2+n)*ArcSinh(m*x)-m*x*Hypergeometric2F1(1/2,1+n/2,2+n/2,-m^2*x^2)))/((1+n)*(2+n))
return F.Times(F.Power(F.Times(F.Plus(F.C1, n), F.Plus(F.C2, n)), F.CN1),
F.Power(x, F.Plus(F.C1, n)),
F.Plus(F.Times(F.Plus(F.C2, n), F.ArcSinh(F.Times(m, x))),
F.Times(F.CN1, m, x, F.Hypergeometric2F1(F.C1D2, F.Plus(F.C1, F.Times(F.C1D2, n)),
F.Plus(F.C2, F.Times(F.C1D2, n)), F.Times(F.CN1, F.Sqr(m), F.Sqr(x))))));
case ID.ArcTan:
// x^(1+n)/((1+n)*(2+n))*((2+n)*ArcTan(m*x)-m*x*Hypergeometric2F1(1,1+n/2,2+n/2,-m^2*x^2))
return F.Times(F.Power(F.Times(F.Plus(F.C1, n), F.Plus(F.C2, n)), F.CN1),
F.Power(x, F.Plus(F.C1, n)),
F.Plus(F.Times(F.Plus(F.C2, n), F.ArcTan(F.Times(m, x))),
F.Times(F.CN1, m, x, F.Hypergeometric2F1(F.C1, F.Plus(F.C1, F.Times(F.C1D2, n)),
F.Plus(F.C2, F.Times(F.C1D2, n)), F.Times(F.CN1, F.Sqr(m), F.Sqr(x))))));
case ID.ArcTanh:
// (x^(1+n)*((2+n)*ArcTanh(m*x)-m*x*Hypergeometric2F1(1,1+n/2,2+n/2,m^2*x^2)))/((1+n)*(2+n))
return F.Times(F.Power(F.Times(F.Plus(F.C1, n), F.Plus(F.C2, n)), F.CN1),
F.Power(x, F.Plus(F.C1, n)),
F.Plus(F.Times(F.Plus(F.C2, n), F.ArcTanh(F.Times(m, x))),
F.Times(F.CN1, m, x, F.Hypergeometric2F1(F.C1, F.Plus(F.C1, F.Times(F.C1D2, n)),
F.Plus(F.C2, F.Times(F.C1D2, n)), F.Times(F.Sqr(m), F.Sqr(x))))));
}
return POWER_TIMES_FUNCION_MATCHER.apply(F.List(unaryFunction.head(), x, n, m));
}
return F.NIL;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.matheclipse.core.reflection.system.rules;

import static org.matheclipse.core.expression.F.*;
import org.matheclipse.core.interfaces.IAST;

/**
* <p>Generated by <code>org.matheclipse.core.preprocessor.RulePreprocessor</code>.</p>
* <p>See GIT repository at: <a href="https://github.com/axkr/symja_android_library">github.com/axkr/symja_android_library under the tools directory</a>.</p>
*/
public class IntegratePowerTimesFunctionRules {
final public static IAST RULES = List(
// {ArcCos,x_,n_,m_}:=(x^(1+n)*((2+n)*ArcCos(m*x)+m*x*Hypergeometric2F1(1/2,1+n/2,2+n/2,m^2*x^2)))/((1+n)*(2+n))
SetDelayed(List(ArcCos,x_,n_,m_),
Times(Power(Times(Plus(C1,n),Plus(C2,n)),CN1),Power(x,Plus(C1,n)),Plus(Times(Plus(C2,n),ArcCos(Times(m,x))),Times(m,x,Hypergeometric2F1(C1D2,Plus(C1,Times(C1D2,n)),Plus(C2,Times(C1D2,n)),Times(Sqr(m),Sqr(x))))))),
// {ArcCosh,x_,n_,m_}:=(x^(1+n)*(ArcCosh(m*x)+(-m*x*Sqrt(1-m^2*x^2)*Hypergeometric2F1(1/2,1+n/2,2+n/2,m^2*x^2))/((2+n)*Sqrt(-1+m*x)*Sqrt(1+m*x))))/(1+n)
SetDelayed(List(ArcCosh,x_,n_,m_),
Times(Power(Plus(C1,n),CN1),Power(x,Plus(C1,n)),Plus(ArcCosh(Times(m,x)),Times(CN1,m,x,Sqrt(Plus(C1,Times(CN1,Sqr(m),Sqr(x)))),Power(Times(Plus(C2,n),Sqrt(Plus(CN1,Times(m,x))),Sqrt(Plus(C1,Times(m,x)))),CN1),Hypergeometric2F1(C1D2,Plus(C1,Times(C1D2,n)),Plus(C2,Times(C1D2,n)),Times(Sqr(m),Sqr(x))))))),
// {ArcCot,x_,n_,m_}:=(x^(1+n)*((2+n)*ArcCot(m*x)+m*x*Hypergeometric2F1(1,1+n/2,2+n/2,-m^2*x^2)))/((1+n)*(2+n))
SetDelayed(List(ArcCot,x_,n_,m_),
Times(Power(Times(Plus(C1,n),Plus(C2,n)),CN1),Power(x,Plus(C1,n)),Plus(Times(Plus(C2,n),ArcCot(Times(m,x))),Times(m,x,Hypergeometric2F1(C1,Plus(C1,Times(C1D2,n)),Plus(C2,Times(C1D2,n)),Times(CN1,Sqr(m),Sqr(x))))))),
// {ArcCoth,x_,n_,m_}:=(x^(1+n)*((2+n)*ArcCoth(m*x)-m*x*Hypergeometric2F1(1,1+n/2,2+n/2,m^2*x^2)))/((1+n)*(2+n))
SetDelayed(List(ArcCoth,x_,n_,m_),
Times(Power(Times(Plus(C1,n),Plus(C2,n)),CN1),Power(x,Plus(C1,n)),Plus(Times(Plus(C2,n),ArcCoth(Times(m,x))),Times(CN1,m,x,Hypergeometric2F1(C1,Plus(C1,Times(C1D2,n)),Plus(C2,Times(C1D2,n)),Times(Sqr(m),Sqr(x))))))),
// {ArcSin,x_,n_,m_}:=(x^(1+n)*((2+n)*ArcSin(m*x)-m*x*Hypergeometric2F1(1/2,1+n/2,2+n/2,m^2*x^2)))/((1+n)*(2+n))
SetDelayed(List(ArcSin,x_,n_,m_),
Times(Power(Times(Plus(C1,n),Plus(C2,n)),CN1),Power(x,Plus(C1,n)),Plus(Times(Plus(C2,n),ArcSin(Times(m,x))),Times(CN1,m,x,Hypergeometric2F1(C1D2,Plus(C1,Times(C1D2,n)),Plus(C2,Times(C1D2,n)),Times(Sqr(m),Sqr(x))))))),
// {ArcSinh,x_,n_,m_}:=(x^(1+n)*((2+n)*ArcSinh(m*x)-m*x*Hypergeometric2F1(1/2,1+n/2,2+n/2,-m^2*x^2)))/((1+n)*(2+n))
SetDelayed(List(ArcSinh,x_,n_,m_),
Times(Power(Times(Plus(C1,n),Plus(C2,n)),CN1),Power(x,Plus(C1,n)),Plus(Times(Plus(C2,n),ArcSinh(Times(m,x))),Times(CN1,m,x,Hypergeometric2F1(C1D2,Plus(C1,Times(C1D2,n)),Plus(C2,Times(C1D2,n)),Times(CN1,Sqr(m),Sqr(x))))))),
// {ArcTan,x_,n_,m_}:=x^(1+n)/((1+n)*(2+n))*((2+n)*ArcTan(m*x)-m*x*Hypergeometric2F1(1,1+n/2,2+n/2,-m^2*x^2))
SetDelayed(List(ArcTan,x_,n_,m_),
Times(Power(Times(Plus(C1,n),Plus(C2,n)),CN1),Power(x,Plus(C1,n)),Plus(Times(Plus(C2,n),ArcTan(Times(m,x))),Times(CN1,m,x,Hypergeometric2F1(C1,Plus(C1,Times(C1D2,n)),Plus(C2,Times(C1D2,n)),Times(CN1,Sqr(m),Sqr(x))))))),
// {ArcTanh,x_,n_,m_}:=(x^(1+n)*((2+n)*ArcTanh(m*x)-m*x*Hypergeometric2F1(1,1+n/2,2+n/2,m^2*x^2)))/((1+n)*(2+n))
SetDelayed(List(ArcTanh,x_,n_,m_),
Times(Power(Times(Plus(C1,n),Plus(C2,n)),CN1),Power(x,Plus(C1,n)),Plus(Times(Plus(C2,n),ArcTanh(Times(m,x))),Times(CN1,m,x,Hypergeometric2F1(C1,Plus(C1,Times(C1D2,n)),Plus(C2,Times(C1D2,n)),Times(Sqr(m),Sqr(x)))))))
);
}
10 changes: 10 additions & 0 deletions symja_android_library/rules/IntegratePowerTimesFunctionRules.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
List(ArcCos,x_,n_,m_) := (x^(1+n)*((2+n)*ArcCos(m*x)+m*x*Hypergeometric2F1(1/2,1+n/2,2+n/2,m^2*x^2)))/((1+n)*(2+n)),
List(ArcCosh,x_,n_,m_) := (x^(1+n)*(ArcCosh(m*x)+(-m*x*Sqrt(1-m^2*x^2)*Hypergeometric2F1(1/2,1+n/2,2+n/2,m^2*x^2))/((2+n)*Sqrt(-1+m*x)*Sqrt(1+m*x))))/(1+n),
List(ArcCot,x_,n_,m_) := (x^(1+n)*((2+n)*ArcCot(m*x)+m*x*Hypergeometric2F1(1,1+n/2,2+n/2,-m^2*x^2)))/((1+n)*(2+n)),
List(ArcCoth,x_,n_,m_) := (x^(1+n)*((2+n)*ArcCoth(m*x)-m*x*Hypergeometric2F1(1,1+n/2,2+n/2,m^2*x^2)))/((1+n)*(2+n)),
List(ArcSin,x_,n_,m_) := (x^(1+n)*((2+n)*ArcSin[m*x]-m*x*Hypergeometric2F1[1/2,1+n/2,2+n/2,m^2*x^2]))/((1+n)*(2+n)),
List(ArcSinh,x_,n_,m_) := (x^(1+n)*((2+n)*ArcSinh(m*x)-m*x*Hypergeometric2F1(1/2,1+n/2,2+n/2,-m^2*x^2)))/((1+n)*(2+n)),
List(ArcTan,x_,n_,m_) := x^(1+n)/((1+n)*(2+n))*((2+n)*ArcTan(m*x)-m*x*Hypergeometric2F1(1,1+n/2,2+n/2,-m^2*x^2)),
List(ArcTanh,x_,n_,m_) := (x^(1+n)*((2+n)*ArcTanh(m*x)-m*x*Hypergeometric2F1(1,1+n/2,2+n/2,m^2*x^2)))/((1+n)*(2+n))
}
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,8 @@ public static void generateFunctionStrings(final File sourceLocation, File targe
}

private static boolean isSpecialRuleList(String className) {
return className.equals("FunctionExpandRules")
return className.equals("IntegratePowerTimesFunctionRules")
|| className.equals("FunctionExpandRules")
|| className.equals("FunctionRangeRules")
|| className.equals("PodDefaultsRules");
}
Expand Down

0 comments on commit 90605ac

Please sign in to comment.