
uk.ac.leeds.ccg.grids.d2.util.Grids_Kernel Maven / Gradle / Ivy
/*
* Copyright 2019 Andy Turner, University of Leeds.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package uk.ac.leeds.ccg.grids.d2.util;
import uk.ac.leeds.ccg.grids.d2.grid.Grids_GridNumber;
import java.math.BigDecimal;
import java.math.RoundingMode;
import uk.ac.leeds.ccg.math.Math_BigDecimal;
import uk.ac.leeds.ccg.grids.d2.Grids_Point;
/**
* For kernels.
*
* @author Andy Turner
* @version 1.0.0
*/
public abstract class Grids_Kernel {
/**
* @param value The value.
* @param mean The mean.
* @param variance The variance.
* @param PI Pi
* @param E euler-macheroni constant
* @param dp Decimal place precision for BigDecimal arithmetic.
* @param rm RoundingMode for BigDecimal arithmetic.
* @return Expected value of value for a normal distribution with mean and
* variance.
*/
public static BigDecimal getNormalDistributionKernelWeight(BigDecimal value,
BigDecimal mean, BigDecimal variance, BigDecimal PI, BigDecimal E,
int dp, RoundingMode rm) {
BigDecimal two = BigDecimal.valueOf(2);
return Math_BigDecimal.divideRoundIfNecessary(BigDecimal.ONE,
variance.multiply(Math_BigDecimal.sqrt(two.multiply(PI), dp, rm)), dp, rm)
.multiply(Math_BigDecimal.power(E, (BigDecimal.ONE.negate().multiply(
Math_BigDecimal.divideRoundIfNecessary(value.subtract(mean).pow(2),
two.multiply(variance.pow(2)), dp, rm))), dp, rm));
}
/**
* @param value The value.
* @param mean The mean.
* @param variance The variance.
* @return Expected value of value for a normal distribution with mean and
* variance.
*/
public static double getNormalDistributionKernelWeight(double value,
double mean, double variance) {
return (1.0d / (variance * Math.sqrt(2.0d * Math.PI)))
* Math.pow(Math.E, (-1.0d * (((value - mean) * (value - mean))
/ (2.0d * variance * variance))));
}
/**
* @param cellsize The cellsize.
* @param distance The distance.
* @return Kernel weights based on the normal distribution. The
* mean and variance of the normal distribution is given by the distances to
* the centroids of the cells that are within distance.
*/
public static double[][] getNormalDistributionKernelWeights(double cellsize,
double distance) {
double[][] r;
int delta = (int) Math.ceil(distance / cellsize);
int squareSize = (delta * 2) + 1;
r = new double[squareSize][squareSize];
int distance2;
int i;
int j;
double meanSquared = 0.0d;
double mean;
double varianceSquared = 0.0d;
double variance;
double numberOfCentroids = 0.0d;
int delta2 = delta * delta;
// Calculate mean distance
for (i = -delta; i <= delta; i++) {
for (j = -delta; j <= delta; j++) {
distance2 = (i * i) + (j * j);
if (distance2 <= delta2) {
numberOfCentroids++;
meanSquared += distance2;
}
}
}
meanSquared /= numberOfCentroids;
mean = Math.sqrt(meanSquared);
// Calculate the variance of distance
for (i = -delta; i <= delta; i++) {
for (j = -delta; j <= delta; j++) {
distance2 = (i * i) + (j * j);
if (distance2 <= delta2) {
varianceSquared += (distance2 - meanSquared)
* (distance2 - meanSquared);
}
}
}
variance = Math.sqrt(varianceSquared);
variance /= (numberOfCentroids - 1.0d);
// Calculate the weights (expected values)
for (i = -delta; i <= delta; i++) {
for (j = -delta; j <= delta; j++) {
distance2 = (i * i) + (j * j);
if (distance2 <= delta2) {
r[i + delta][j + delta] = getNormalDistributionKernelWeight(
Math.sqrt((double) distance2), mean, variance);
} else {
//weights[ i + delta ][ j + delta ] = noDataValue;
r[i + delta][j + delta] = 0.0d;
}
}
}
return r;
}
/**
* @return A value for the height of a kernel at thisDistance from the
* centre of a kernel with; bandwidth distance, weight at the centre of
* weightIntersect and distance decay of weightFactor.
*
* @param d Bandwidth of the kernel.
* @param wi Weight at the centre of the kernel.
* @param wf Warning: If less than 1 then strange things could happen!!!!
* @param td The distance from the centre of the kernel that the weight
* result is returned.
* @param dp Decimal place precision for BigDecimal arithmetic.
* @param rm RoundingMode for BigDecimal arithmetic.
*/
public static BigDecimal getKernelWeight(BigDecimal d, BigDecimal wi,
int wf, BigDecimal td, int dp, RoundingMode rm) {
return BigDecimal.ONE.subtract((Math_BigDecimal.divideRoundIfNecessary(
td.pow(2), d.pow(2), dp, rm))).pow(wf).multiply(wi);
}
/**
* Get kernel weights.
*
* @param g The grid.
* @param d The distance.
* @param wi The weight intersect.
* @param wf The weight factor.
* @param dp Decimal place precision for BigDecimal arithmetic.
* @param rm RoundingMode for BigDecimal arithmetic.
* @return Kernel weights.
*/
public static BigDecimal[][] getKernelWeights(Grids_GridNumber g,
BigDecimal d, BigDecimal wi, int wf, int dp, RoundingMode rm) {
BigDecimal cellsize = g.getCellsize();
int delta = d.divideToIntegralValue(cellsize).intValueExact();
BigDecimal[][] weights = new BigDecimal[(delta * 2) + 1][(delta * 2) + 1];
/**
* The following weight is just one example of a kernel that can be
* used! It provides a general monotonic curve based on distance over
* bandwidth.
*/
BigDecimal x0 = g.getCellX(0L);
BigDecimal y0 = g.getCellY(0L);
BigDecimal x1;
BigDecimal y1;
BigDecimal thisDistance;
int row;
int col;
for (row = -delta; row <= delta; row++) {
for (col = -delta; col <= delta; col++) {
x1 = g.getCellX(col);
y1 = g.getCellY(row);
thisDistance = Grids_Utilities.distance(x0, y0, x1, y1, dp, rm);
//if ( thisDistance <= distance ) {
if (thisDistance.compareTo(d) == -1) {
weights[row + delta][col + delta] = getKernelWeight(
d, wi,
wf, thisDistance, dp, rm);
} else {
//weights[ i + cellDistance ][ j + cellDistance ] = noDataValue;
weights[row + delta][col + delta] = BigDecimal.ZERO;
}
}
}
return weights;
}
/**
* Get kernel weights.
*
* @param g The grid.
* @param row The cell row.
* @param col The cell column.
* @param d The distance.
* @param wi The weight intersect.
* @param wf The weight factor.
* @param points The points.
* @param dp Decimal place precision for BigDecimal arithmetic.
* @param rm RoundingMode for BigDecimal arithmetic.
* @return Kernel weights.
*/
public static BigDecimal[] getKernelWeights(Grids_GridNumber g, long row,
long col, BigDecimal d, BigDecimal wi, int wf, Grids_Point[] points,
int dp, RoundingMode rm) {
BigDecimal[] weights = new BigDecimal[points.length];
/**
* The following weight is just one example of a kernel that can be
* used! It provides a general monotonic curve based on distance over
* bandwidth.
*/
BigDecimal x = g.getCellX(col);
BigDecimal y = g.getCellY(row);
for (int i = 0; i < points.length; i++) {
BigDecimal td = Grids_Utilities.distance(x, y, points[i].x,
points[i].y, dp, rm);
if (td.compareTo(d) == -1) {
weights[i] = getKernelWeight(d, wi, wf, td, dp, rm);
}
}
return weights;
}
/**
* Get kernel weights.
*
* @param centroid The centroid.
* @param d The distance.
* @param wi The weight intersect.
* @param wf The weight factor.
* @param points The points.
* @param dp Decimal place precision for BigDecimal arithmetic.
* @param rm RoundingMode for BigDecimal arithmetic.
* @return Kernel weights.
*/
public static BigDecimal[] getKernelWeights(Grids_Point centroid,
BigDecimal d, BigDecimal wi, int wf, Grids_Point[] points, int dp,
RoundingMode rm) {
BigDecimal[] weights = new BigDecimal[points.length];
/**
* The following weight is just one example of a kernel that can be
* used! It provides a general monotonic curve based on distance over
* bandwidth.
*/
for (int i = 0; i < points.length; i++) {
BigDecimal td = Grids_Utilities.distance(centroid.x, centroid.y,
points[i].x, points[i].y, dp, rm);
if (td.compareTo(d) == -1) {
weights[i] = getKernelWeight(d, wi, wf, td, dp, rm);
}
}
return weights;
}
/**
* Get kernel parameters:
*
* - [0] = The total sum of all the weights for a given kernel
* - [1] = The total number of cells that's centroids are within distance
* of an arbitrary cell centroid of grid.
*
*
* @param g The grid.
* @param cd The cell distance.
* @param d The distance.
* @param wi The weight intersect.
* @param wf The weight factor.
* @param dp Decimal place precision for BigDecimal arithmetic.
* @param rm RoundingMode for BigDecimal arithmetic.
* @return Kernel parameters.
*/
public static BigDecimal[] getKernelParameters(Grids_GridNumber g, int cd,
BigDecimal d, BigDecimal wi, int wf, int dp, RoundingMode rm) {
BigDecimal r[] = new BigDecimal[2];
r[0] = BigDecimal.ZERO;
r[1] = BigDecimal.ZERO;
BigDecimal x0 = g.getCellX(0);
BigDecimal y0 = g.getCellY(0);
for (int p = -cd; p <= cd; p++) {
for (int q = -cd; q <= cd; q++) {
BigDecimal x1 = g.getCellX(q);
BigDecimal y1 = g.getCellY(p);
BigDecimal td = Grids_Utilities.distance(x0, y0, x1, y1, dp,
rm);
if (td.compareTo(d) == -1) {
r[0] = r[0].add(getKernelWeight(d, wi, wf, td, dp, rm));
r[1] = r[1].add(BigDecimal.ONE);
}
}
}
return r;
}
/**
* Get adaptive kernel weight.
*
* @param d The distance.
* @param bw The bandwidth.
* @param sw The sum weights.
* @param p The precision.
* @param wi The weight intersect.
* @param wf The weight factor.
* @param dp Decimal place precision for BigDecimal arithmetic.
* @param rm RoundingMode for BigDecimal arithmetic.
* @return Adaptive kernel weight.
*/
public static BigDecimal getAdaptiveKernelWeight(BigDecimal d,
BigDecimal bw, BigDecimal sw, int p, BigDecimal wi, int wf,
int dp, RoundingMode rm) {
BigDecimal kernelVolume = getKernelVolume(bw, p, wi, wf, dp, rm);
BigDecimal kernelWeight = getKernelWeight(bw, wi, wf, d, dp, rm);
return Math_BigDecimal.divideRoundIfNecessary(kernelWeight.multiply(sw),
kernelVolume, dp, rm);
}
/**
* Get the kernel volume.
*
* @param bw The bandwidth.
* @param p The precision.
* @param wi The weight intersect.
* @param wf The weight factor.
* @param dp Decimal place precision for BigDecimal arithmetic.
* @param rm RoundingMode for BigDecimal arithmetic.
* @return The kernel volume.
*/
public static BigDecimal getKernelVolume(BigDecimal bw, int p,
BigDecimal wi, int wf, int dp, RoundingMode rm) {
BigDecimal r = BigDecimal.ZERO;
BigDecimal[] dar = bw.divideAndRemainder(BigDecimal.valueOf(p));
BigDecimal sectionSize = dar[0];
if (dar[1].compareTo(BigDecimal.ZERO) == 1) {
sectionSize = sectionSize.add(BigDecimal.ONE);
}
BigDecimal sectionArea = sectionSize.multiply(sectionSize);
//int sectionCount = 0;
for (int row = 1; row < p; row++) {
for (int col = 0; col < p; col++) {
BigDecimal td = Grids_Utilities.distance(BigDecimal.ZERO,
BigDecimal.ZERO, BigDecimal.valueOf(row)
.multiply(sectionSize),
BigDecimal.valueOf(col).multiply(sectionSize), dp, rm);
if (td.compareTo(bw) == -1) {
r = r.add(
getKernelWeight(bw, wi, wf, td, dp, rm));
//sectionCount ++;
}
}
}
// Multiply by 4 for all quadrants
// Add kernelCentroid weight
// Multiply result be sectionArea to get volume
return (r.multiply(BigDecimal.valueOf(4)).add(wi)).multiply(sectionArea);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy