com.github.psambit9791.jdsp.misc.UtilMethods Maven / Gradle / Ivy
/*
* Copyright (c) 2020 Sambit Paul
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.github.psambit9791.jdsp.misc;
import org.apache.commons.math3.analysis.interpolation.LinearInterpolator;
import org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction;
import org.apache.commons.math3.linear.DecompositionSolver;
import org.apache.commons.math3.linear.MatrixUtils;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.linear.SingularValueDecomposition;
import org.apache.commons.math3.stat.StatUtils;
import java.io.*;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
/**
* Utility Methods
* The UtilMethods class implements different utility functions to help with mathematical operations
*
*
* @author Sambit Paul
* @version 1.0
*/
public class UtilMethods {
/**
* This function returns evenly spaced number over a specified interval such that there are specified number of samples.
* This is equivalent of the numpy linspace() function.
* @param start Start value of the sequence
* @param stop Stop value of the sequence
* @param samples Number of samples to be generated
* @param includeEnd Include stop value in the sequence
* @return double[] Generated sequence
*/
public static double[] linspace(int start, int stop, int samples, boolean includeEnd) {
double[] time = new double[samples];
double T;
double span = stop - start;
double stopVal = (double) stop;
double i = start;
if (includeEnd) {
T = span/(samples-1);
}
else {
T = span/samples;
stopVal = stopVal - T;
}
int index = 0;
time[index] = i;
for (index=1; indexlinspace() function.
* @param start Start value of the sequence
* @param stop Stop value of the sequence
* @param samples Number of samples to be generated
* @param includeEnd Include stop value in the sequence
* @return double[] Generated sequence
*/
public static double[] linspace(double start, double stop, int samples, boolean includeEnd) {
double[] time = new double[samples];
double T;
double span = stop - start;
double stopVal = (double) stop;
double i = start;
if (includeEnd) {
T = span/(samples-1);
}
else {
T = span/samples;
stopVal = stopVal - T;
}
int index = 0;
time[index] = i;
for (index=1; index 0.00001) {
i = i + T;
index++;
time[index] = i;
}
double[] out = {};
for (int j = 0; jlinspace() function.
* @param start Start value of the sequence
* @param stop Stop value of the sequence
* @param step Spacing between elements
* @throws java.lang.IllegalArgumentException If start value is greater than stop value
* @return double[] Generated sequence
*/
public static double[] arange(double start, double stop, double step) {
if (start > stop) {
throw new IllegalArgumentException("start cannot be greater than stop");
}
int size = (int)((stop-start)/step);
double[] arr = new double[size];
double temp = start;
for (int i=0; ilinspace() function.
* @param start Start value of the sequence
* @param stop Stop value of the sequence
* @param step Spacing between elements
* @throws java.lang.IllegalArgumentException If start value is greater than stop value
* @return int[] Generated sequence
*/
public static int[] arange(int start, int stop, int step) {
if (start > stop) {
throw new IllegalArgumentException("start cannot be greater than stop");
}
int size = (stop - start)/step;
int[] arr = new int[size];
int temp = start;
for (int i=0; i=0; i--) {
inv[index] = arr[i];
index++;
}
return inv;
}
/**
* This function returns the input array after reversing the order of the elements in it.
* @param arr Array to be reversed
* @return int[] Reversed array
*/
public static int[] reverse(int[] arr) {
int[] inv = new int[arr.length];
int index = 0;
for (int i=(arr.length-1); i>=0; i--) {
inv[index] = arr[i];
index++;
}
return inv;
}
// Concatenate 2 arrays
/**
* This function returns the concatenation of the 2 input arrays.
* @param arr1 Array to be added first
* @param arr2 Array to be added second
* @return double[] Concatenated array
*/
public static double[] concatenateArray(double[] arr1, double[] arr2) {
double[] out = new double[arr1.length + arr2.length];
System.arraycopy(arr1, 0, out, 0, arr1.length);
System.arraycopy(arr2, 0, out, arr1.length, arr2.length);
return out;
}
/**
* This function returns the concatenation of the 2 input arrays.
* @param arr1 Array to be added first
* @param arr2 Array to be added second
* @return int[] Concatenated array
*/
public static int[] concatenateArray(int[] arr1, int[] arr2) {
int[] out = new int[arr1.length + arr2.length];
System.arraycopy(arr1, 0, out, 0, arr1.length);
System.arraycopy(arr2, 0, out, arr1.length, arr2.length);
return out;
}
// Split an array by indices
/**
* This function returns the concatenation of the 2 input arrays.
* @param arr Array to be manipulated
* @param start Start index for split
* @param end Stop index for split
* @return double[] Sub-array generated by splitting input array by start and end indices
*/
public static double[] splitByIndex(double[] arr, int start, int end) {
double[] out = new double[end-start];
System.arraycopy(arr, start, out, 0, out.length);
return out;
}
/**
* This function returns the concatenation of the 2 input arrays.
* @param arr Array to be manipulated
* @param start Start index for split
* @param end Stop index for split
* @return int[] Sub-array generated by splitting input array by start and end indices
*/
public static int[] splitByIndex(int[] arr, int start, int end) {
int[] out = new int[end-start];
System.arraycopy(arr, start, out, 0, out.length);
return out;
}
// Find pseudo-inverse of a 2D array
/**
* This function returns the pseudo-inverse of a 2D matrix.
* @param mtrx 2D matrix
* @return double[][] Pseudo-inverse of the input matrix
*/
public static double[][] pseudoInverse(double[][] mtrx) {
RealMatrix M = MatrixUtils.createRealMatrix(mtrx);
DecompositionSolver solver = new SingularValueDecomposition(M).getSolver();
return solver.getInverse().getData();
}
// Different methods of padding a signal
/**
* This function returns the input signal by padding it.
* The output differs based on the mode of operation.
* @param signal Signal to be padded
* @param mode The mode in which padding will take place
* @throws java.lang.IllegalArgumentException If string mode is not "reflect", "constant", "nearest", "mirror" or "wrap"
* Mode outputs for signal [a b c d]:
* "reflect" : [d c b a | a b c d | d c b a]
* "constant" : [0 0 0 0 | a b c d | 0 0 0 0]
* "nearest" : [a a a a | a b c d | d d d d]
* "mirror" : [c d c b | a b c d | c b a b]
* "wrap" : [a b c d | a b c d | a b c d]
* @return double[][] Pseudo-inverse of the input matrix
*/
public static double[] padSignal(double[] signal, String mode) {
double[] newSignal = {};
if (mode.equals("reflect")) {
double[] revSig = reverse(signal);
double[] newSig = {};
newSig = concatenateArray(newSig, revSig);
newSig = concatenateArray(newSig, signal);
newSig = concatenateArray(newSig, revSig);
newSignal = newSig;
}
else if (mode.equals("constant")) {
double[] cons = new double[signal.length];
Arrays.fill(cons, 0);
double[] newSig = {};
newSig = concatenateArray(newSig, cons);
newSig = concatenateArray(newSig, signal);
newSig = concatenateArray(newSig, cons);
newSignal = newSig;
}
else if (mode.equals("nearest")) {
double[] left = new double[signal.length];
Arrays.fill(left, signal[0]);
double[] right = new double[signal.length];
Arrays.fill(right, signal[signal.length-1]);
double[] newSig = {};
newSig = concatenateArray(newSig, left);
newSig = concatenateArray(newSig, signal);
newSig = concatenateArray(newSig, right);
newSignal = newSig;
}
else if (mode.equals("mirror")) {
double[] temp = splitByIndex(signal, 1, signal.length);
temp = reverse(temp);
double[] val = new double[]{temp[1]};
double[] left = concatenateArray(val, temp);
temp = splitByIndex(signal, 0, signal.length-1);
temp = reverse(temp);
val = new double[]{temp[temp.length - 2]};
double[] right = concatenateArray(temp, val);
double[] newSig = {};
newSig = concatenateArray(newSig, left);
newSig = concatenateArray(newSig, signal);
newSig = concatenateArray(newSig, right);
newSignal = newSig;
}
else if (mode.equals("wrap")) {
double[] newSig = {};
newSig = concatenateArray(newSig, signal);
newSig = concatenateArray(newSig, signal);
newSig = concatenateArray(newSig, signal);
newSignal = newSig;
}
else {
throw new IllegalArgumentException("padSignalforConvolution modes can only be reflect, constant, " +
"nearest, mirror, wrap or interp (default)");
}
return newSignal;
}
/**
* Implementation of the numpy version of diff()
* Calculate the first discrete difference in the array
* @param arr The array to be processed
* @return double[] The discrete difference array
*/
public static double[] diff(double[] arr) {
double[] sig = new double[arr.length-1];
for (int i=0; iStackoverflow answer helped implement this function.
* @param x The abscissa (horizontal axis)
* @param y The ordinate (vertical axis)
* @return PolynomialSplineFunction The interpolation function
*/
private static PolynomialSplineFunction linearInterp(double[] x, double[] y) {
LinearInterpolator li = new LinearInterpolator();
PolynomialSplineFunction psf = li.interpolate(x, y);
return psf;
}
/**
* Converts an Integer ArrayList to int[] array
* @param l The Integer ArrayList
* @return int[] The primitive array
*/
public static int[] convertToPrimitiveInt(ArrayList l) {
int[] ret = new int[l.size()];
for (int i=0; i l) {
double[] ret = new double[l.size()];
for (int i=0; i() {
@Override
public int compare(final Integer i1, final Integer i2) {
return (ascending ? 1 : -1) * Double.compare(arr[i1], arr[i2]);
}
});
for (int i=0; i