lib/integral.js
function(expr, context, subIntegral) {
      var MaxExponentExpanded = 10;

      if(expr.type === 'OperatorNode' && expr.op === '^') {
        var multipliedOut = tryMultiplyOut(expr);
        if(multipliedOut) {
          var int = subIntegral(multipliedOut, context, "reducing power");
          if(int) {
            return int;
          }
        }
      } else if(expr.type === 'OperatorNode' && expr.op === '*') {
        for(var i = 0; i < expr.args.length; i++) {
          var multipliedOutChild = tryMultiplyOut(expr.args[i]);
          if(multipliedOutChild) {
            var int = subIntegral(new OperatorNode('*', 'multiply', multipliedOutChild.args.concat(
              expr.args.slice(0, i),
              expr.args.slice(i+1)
            )), context, "reducing power");

            if(int) {
              return int;
            }
          }
        }
      }

      //
      function tryMultiplyOut(expr) {
        if(expr.type === 'OperatorNode' && expr.op === '^' && !context.isConstant(expr.args[0])) {
          var exponentValue = getNumericValue(expr.args[1]);
          if(Number.isInteger(exponentValue) && exponentValue > 1 && exponentValue <= MaxExponentExpanded) {
            return new OperatorNode('*', 'multiply', [
              expr.args[0],
              exponentValue === 2 ? expr.args[0] : new OperatorNode('^', 'pow', [
                expr.args[0],
                new ConstantNode(exponentValue-1)
              ])
            ]);
          }
        }

        return null;
      }
    }
function(expr, context, subIntegral) {
      var MaxExponentExpanded = 10;

      if(expr.type === 'OperatorNode' && expr.op === '^') {
        var multipliedOut = tryMultiplyOut(expr);
        if(multipliedOut) {
          var int = subIntegral(multipliedOut, context, "reducing power");
          if(int) {
            return int;
          }
        }
      } else if(expr.type === 'OperatorNode' && expr.op === '*') {
        for(var i = 0; i < expr.args.length; i++) {
          var multipliedOutChild = tryMultiplyOut(expr.args[i]);
          if(multipliedOutChild) {
            var int = subIntegral(new OperatorNode('*', 'multiply', multipliedOutChild.args.concat(
              expr.args.slice(0, i),
              expr.args.slice(i+1)
            )), context, "reducing power");

            if(int) {
              return int;
            }
          }
        }
      }

      //
      function tryMultiplyOut(expr) {
        if(expr.type === 'OperatorNode' && expr.op === '^' && !context.isConstant(expr.args[0])) {
          var exponentValue = getNumericValue(expr.args[1]);
          if(Number.isInteger(exponentValue) && exponentValue > 1 && exponentValue <= MaxExponentExpanded) {
            return new OperatorNode('*', 'multiply', [
              expr.args[0],
              exponentValue === 2 ? expr.args[0] : new OperatorNode('^', 'pow', [
                expr.args[0],
                new ConstantNode(exponentValue-1)
              ])
            ]);
          }
        }

        return null;
      }
    }
integral(f(x)^c [* g(x)], x) = integral(f(x) * f(x)^(c-1) [* g(x)], x) However, we only expand for c<=10 to save computational resources