package org.matheclipse.core.reflection.system;
import static org.matheclipse.core.expression.F.BernoulliB;
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.C2;
import static org.matheclipse.core.expression.F.CN1;
import static org.matheclipse.core.expression.F.ExpandAll;
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.Slot;
import static org.matheclipse.core.expression.F.Sum;
import static org.matheclipse.core.expression.F.Times;
import static org.matheclipse.core.expression.F.k;
import java.util.HashMap;
import org.matheclipse.core.eval.exception.Validate;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.generic.Functors;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.IInteger;
import org.matheclipse.core.interfaces.ISymbol;
import com.google.common.base.Predicate;
/**
* Summation of expressions.
*
* See Wikipedia Summation
*/
public class Sum extends Table {
private static HashMap MAP_0_N = new HashMap();
static {
// Binomial[#2,#] -> 2^#
MAP_0_N.put(Binomial(Slot(C2), Slot(C1)), Power(C2, Slot(C1)));
// #*Binomial[#2,#] -> #*2^(#-1)
MAP_0_N.put(Times(Slot(C1), Binomial(Slot(C2), Slot(C1))), Times(Slot(C1), Power(C2, Plus(Slot(C1), Times(CN1, C1)))));
}
public Sum() {
}
@Override
public IExpr evaluate(final IAST ast) {
Validate.checkRange(ast, 3);
IExpr arg1 = ast.arg1();
if (arg1.isPlus()) {
IAST sum = ast.clone();
sum.set(1, F.Null);
return ((IAST) arg1).map(Functors.replace1st(sum));
}
IExpr arg2 = ast.get(2);
IExpr temp;
if (ast.size() == 3 && arg2.isList() && ((IAST) arg2).size() == 4) {
IAST list = (IAST) arg2;
if (list.arg1().isSymbol() && list.get(2).isInteger() && list.get(3).isSymbol()) {
temp = definiteSum(arg1, list);
if (temp != null) {
return temp;
}
}
} else if (ast.size() == 3 && arg2.isSymbol()) {
temp = indefiniteSum(arg1, (ISymbol) arg2);
if (temp != null) {
return temp;
}
}
IAST resultList = Plus();
temp = evaluateTable(ast, resultList, C0);
if (temp == null || temp.equals(resultList)) {
return null;
}
return temp;
}
/**
* Evaluate the definite sum: Sum[arg1, {var, from, to}]
*
* @param arg1
* the first argument of the Sum[] function.
* @param list
* constructed as {Symbol: var, Integer: from, Symbol: to}
* @return
*/
public IExpr definiteSum(IExpr arg1, final IAST list) {
final ISymbol var = (ISymbol) list.arg1();
final IInteger from = (IInteger) list.get(2);
final ISymbol to = (ISymbol) list.get(3);
if (arg1.isFree(var, true) && arg1.isFree(to, true)) {
if (from.equals(F.C1)) {
return F.Times(to, arg1);
}
if (from.equals(F.C0)) {
return F.Times(Plus(to, C1), arg1);
}
} else {
if (arg1.isTimes()) {
// Sum[ Times[a,b,c,...], {var, from, to} ]
IAST filterCollector = F.Times();
IAST restCollector = F.Times();
((IAST) arg1).filter(filterCollector, restCollector, new Predicate() {
@Override
public boolean apply(IExpr input) {
return input.isFree(var, true) && input.isFree(to, true);
}
});
if (filterCollector.size() > 1) {
if (restCollector.size() == 2) {
filterCollector.add(F.Sum(restCollector.arg1(), list));
} else {
filterCollector.add(F.Sum(restCollector, list));
}
return filterCollector;
}
}
if (from.equals(F.C0)) {
if (arg1.isPower()) {
return sumPower((IAST) arg1, var, to);
} else if (arg1.equals(var)) {
return sumPowerFormula(to, F.C1);
}
IExpr repl = arg1.replaceAll(F.List(F.Rule(var, F.Slot(F.C1)), F.Rule(to, F.Slot(F.C2))));
if (repl != null) {
IExpr temp = MAP_0_N.get(repl);
if (temp != null) {
return temp.replaceAll(F.Rule(F.Slot(F.C1), to));
}
}
}
}
if (from.isPositive()) {
return F.Subtract(F.Sum(arg1, F.List(var, C0, to)), F.Sum(arg1, F.List(var, C0, from.minus(F.C1))));
}
return null;
}
/**
* Evaluate the indefinite sum: Sum[arg1, var]
*
* @param arg1
* @param var
* @return
*/
public IExpr indefiniteSum(IExpr arg1, final ISymbol var) {
if (arg1.isTimes()) {
// Sum[ Times[a,b,c,...], var ]
IAST filterCollector = F.Times();
IAST restCollector = F.Times();
((IAST) arg1).filter(filterCollector, restCollector, new Predicate() {
@Override
public boolean apply(IExpr input) {
return input.isFree(var, true);
}
});
if (filterCollector.size() > 1) {
if (restCollector.size() == 2) {
filterCollector.add(F.Sum(restCollector.arg1(), var));
} else {
filterCollector.add(F.Sum(restCollector, var));
}
return filterCollector;
}
} else if (arg1.isPower()) {
return sumPower((IAST) arg1, var, var);
} else if (arg1.equals(var)) {
return sumPowerFormula(var, F.C1);
}
IExpr repl = arg1.replaceAll(F.List(F.Rule(var, F.Slot(F.C1))));
if (repl != null) {
IExpr temp = MAP_0_N.get(repl);
if (temp != null) {
return temp.replaceAll(F.Rule(F.Slot(F.C1), var));
}
}
return null;
}
/**
* See Wikipedia -
* Summation#Some_summations_of_polynomial_expressions.
*
* @param powAST
* an AST of the form Power[var^i]
* @param var
* @param to
* @return
*/
public IExpr sumPower(final IAST powAST, final ISymbol var, final IExpr to) {
if (powAST.arg1().equals(var) && powAST.get(2).isInteger()) {
IInteger p = (IInteger) powAST.get(2);
if (p.isPositive()) {
return sumPowerFormula(to, p);
}
}
return null;
}
public IExpr sumPowerFormula(final IExpr to, IInteger p) {
// TODO optimize if BernoulliB==0 for odd k != 1
// Sum[var ^ p, var] :=
// (var+1)^(p+1)/(p+1) + Sum[(var+1)^(p-k+1)*Binomial[p,k]*BernoulliB[k]*(p-k+1)^(-1), {k,1,p}]
return F.eval(ExpandAll(Plus(
Times(Power(Plus(to, C1), Plus(p, C1)), Power(Plus(p, C1), CN1)),
Sum(Times(Times(Times(Power(Plus(to, C1), Plus(Plus(p, Times(CN1, k)), C1)), Binomial(p, k)), BernoulliB(k)),
Power(Plus(Plus(p, Times(CN1, k)), C1), CN1)), List(k, C1, p)))));
}
}
Ads help maintain this website.