The functional forms that we saw in Gauss Quadrature are restrictive. Like, for example the Gauss-Legendre formula is [-1,1]. Ofte in times, we want more flexibility in the intervals. The other orms integrate from and/or till infinity, which makes it not very useful to apply to simpler quadrature rules like the trapezoidal or Simpson’s. Moreover, many of the integrals are difficult to calculate as they are very complicated. There are also many functions taht cannot be evaluated at certain points due to singularity. Integration by substitution writes teh integral that needs to be evaluated, in a simpler form so that it is easier to compute such as by avoiding the singularity. It can also transform the integral to a desired range and also to avoid infinity. Moreover, it speeds up the computation by reducing the number of iterations needed for convergence. The substitution rule ays that we find a change of variable,

such that,

We can then replace the integral in with an integral in .

Consider for example, suppose we want to calculate,

If we set , in the above equation, we have

Or, more specifically

Now, substituting these in the original integral and eliminating , we have

The new integral in is easier to compute than the original one.

` ````
```val f: AbstractRealUnivariateFunction = new AbstractUnivariateFunction();
val I: Integrator = new Integrator();
double a = 0, b = 10; // the limits
Integrator integrator1 = new NewtonCotes(3, NewtonCotes.Type.OPEN, 1e-8, 10);
Integrator integrator2 = new ChangeofVariables(new StandardInterval(a, b), integrator1);
double I = integrator2.integrate(
new AbstractRealUnivariateFunctionction() {
override public double evaluate (double t) {
return t; // the original integrand
}
},
a, b // the original limits
);
System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I));

The output is:

` ````
```S_[0,10] f(x) dx = 50.000000

` ````
```val f: AbstractRealUnivariateFunction = new AbstractUnivariateFunction();
val I: Integrator = new Integrator();
double a = 1, b = Double.POSITIVE_INFINITY; // the limits
NewtonCotes integrator1 = new NewtonCotes(3, NewtonCotes.Type.OPEN, 1e-15, 10);
ChangeOfVariable integrator2 = new ChangeofVariable(new InvertingVariable(a, b), integrator1);
double I = integrator2.integrate( // I = 1
new AbstractRealUnivariateFunctionction() {
override public double evaluate (double x) {
return 1 / x / x; // the original integrand
}
},
a, b // the original limits
);
System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I));

The output is:

` ````
```S_[1,Infinity] f(x) dx = 1.000000

` ````
```val f: AbstractRealUnivariateFunction = new AbstractUnivariateFunction();
val I: Integrator = new Integrator();
double a = 1, b = Double.POSITIVE_INFINITY; // the limits
NewtonCotes integrator1 = new NewtonCotes(3, NewtonCotes.Type.OPEN, 1e-15, 10);
ChangeOfVariable integrator2 = new ChangeofVariable(new Exponential(a), integrator1);
double I = integrator2.integrate( // I = sqrt(PI)/2
new AbstractRealUnivariateFunctionction() {
override public double evaluate (double x) {
return sqrt(x) * exp(-x); // the original integrand
}
},
a, b // the original limits
);
System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I));

The output is:

` ````
```S_[0,Infinity] f(x) dx = 0.886227

` ````
```val f: UivariateRealFunction f = new AbstractUnivariateFunction() {
override public double evaluate(double x) {
return exp(-x) * pow(x, -1.5) * sin(x / 2);
}
};
double a = 0, b = Double.POSITIVE.INFINITY; // the limits
NewtonCotes integrator1 = new NewtonCotes(2, NewtonCotes.Type.OPEN, 1e-15, 7); // only 7 iterations
ChangeOfVariable integrator2 = new ChangeofVariable(new MixedRule(f, a, b, 1), integrator1);
double I = integrator2.integrate(f, a, b); // I = sqrt(PI * (sqrt(5) - 2))
System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I));

The output is:

` ````
```S_[0,Infinity] f(x) dx = 0.861179

` ````
```val f: UivariateRealFunction f = new AbstractUnivariateFunction() {
override public double evaluate(double x) {
return log(x) * log(1 - x);
}
};
double a = 0, b = 1; // the limits
NewtonCotes integrator1 = new NewtonCotes(2, NewtonCotes.Type.CLOSED, 1e-15, 6); // only 6 iterations
ChangeOfVariable integrator2 = new ChangeofVariable(new DoubleExponential(f, a, b, 1), integrator1);
double I = integrator2.integrate(f, a, b); // I = 2 - PI * PI / 6
System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I));

The output is:

` ````
```S_[0,1] f(x) dx = 0.355066

` ````
```val f: UivariateRealFunction f = new AbstractUnivariateFunction() {
override public double evaluate(double x) {
return exp(-x * x);
}
};
double a = Double.NEGATIVE_INFINITY, b = Double.POSITIVE_INFINITY; // the limits
NewtonCotes integrator1 = new NewtonCotes(3, NewtonCotes.Type.CLOSED, 1e-15, 6); // only 6 iterations
ChangeOfVariable integrator2 = new ChangeofVariable(new DoubleExponential4RealLine(f, a, b, 1), integrator1);
double I = integrator2.integrate(f, a, b); // sqrt(PI
System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I));

The output is:

` ````
```S_[-Infinity,Infinity] f(x) dx = 1.772454

` ````
```val f: UivariateRealFunction f = new AbstractUnivariateFunction() {
override public double evaluate(double x) {
return x / (exp(x) - 1);
}
};
double a = Double.NEGATIVE_INFINITY, b = Double.POSITIVEINFINITY; // the limits
NewtonCotes integrator1 = new NewtonCotes(3, NewtonCotes.Type.OPEN, 1e-15, 15);
ChangeOfVariable integrator2 = new ChangeofVariable(new DoubleExponential4HalfRealLine(f, a, b, 1), integrator);
double I = instance.integrate(f, a, b); // PI * PI / 6
System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I));

The output is:

` ````
```S_[-Infinity,Infinity] f(x) dx = 1.772454

## Power Law Singularity

For singularity at the lower limits, we have diverging near , .

The substitution rule for the same is,

For singularity at the upper limit, we have diverging near , .

The substitution rule is,

A common case is when .

` ````
```double a = 1, b = 2; // the limits
NewtonCotes integrator1 = new NewtonCotes(3, NewtonCotes.Type.OPEN, 1e-15, 15);
ChangeOfVariable integrator2 = new ChangeOfVariable(
new PowerLawSingularity(PowerLawSingularity.PowerLawSingularityType.LOWER,
0.5, // gamma = 0.15
a, b),
integrator1);
double I = integrator2.integrate( // I =
new AbstractUnivariateRealFunction() {
override public double evaluate(double x) {
return 1 / sqrt(x - 1);
}
},
a, b
);
System.out.println(String.format("S_[%.0f,%.0f] f(x) dx = %f", a, b, I));

The output is:

` ````
```S_[1,2] f(x) dx = 2.000000