diff --git a/.gitignore b/.gitignore index 8d47cace3a5bd898da9fb12bed716d60838191a4..57f16fb67c1b1589981416b323d7a9debc728665 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,41 @@ -.idea/ +/build* +/workspace +setting.xml +release/ target/ -.settings/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ +icy.log + +### IntelliJ IDEA ### +.idea/ +*.iws *.iml -.project +*.ipr + +### Eclipse ### +.apt_generated .classpath -**/.DS_Store \ No newline at end of file +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +**/.DS_Store +Icon? \ No newline at end of file diff --git a/pom.xml b/pom.xml index afc615e79a836d11c4c0371a75c718d783dfe7ff..f8789ab8662af8a9e6cf0e2bd02e77ce0e6013b5 100644 --- a/pom.xml +++ b/pom.xml @@ -8,12 +8,12 @@ <parent> <groupId>org.bioimageanalysis.icy</groupId> <artifactId>pom-icy</artifactId> - <version>2.2.0</version> + <version>3.0.0-a.1</version> </parent> <!-- Project Information --> <artifactId>flanagan</artifactId> - <version>2.0.0</version> + <version>2.0.0-a.1</version> <name>Flanagan</name> <description> @@ -56,32 +56,26 @@ </developer> </developers> - <!-- Project properties --> - <properties> - <artifact-to-extract>flanagan</artifact-to-extract> - </properties> - <!-- List of project's dependencies --> <dependencies> - <dependency> + <!--<dependency> <groupId>flanagan</groupId> <artifactId>flanagan</artifactId> <version>1.0</version> - </dependency> + </dependency>--> </dependencies> <!-- Icy Maven repository (to find parent POM) --> <repositories> - <repository> + <!--<repository> <id>pavlab</id> <name>PavLab</name> <url>https://maven2.pavlab.msl.ubc.ca/</url> - </repository> + </repository>--> <repository> <id>icy</id> - <name>Icy's Nexus</name> - <url>https://icy-nexus.pasteur.fr/repository/Icy/</url> + <url>https://nexus-icy.pasteur.cloud/repository/icy/</url> </repository> </repositories> </project> diff --git a/src/main/java/flanagan/analysis/BoxCox.java b/src/main/java/flanagan/analysis/BoxCox.java new file mode 100755 index 0000000000000000000000000000000000000000..7f884f3e6d58647f585a378b9c9da2bb6d0d0695 --- /dev/null +++ b/src/main/java/flanagan/analysis/BoxCox.java @@ -0,0 +1,801 @@ +/* +* Class BoxCox +* +* USAGE: Box-Cox Transformation +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: July - August 2008 +* AMENDED: 2-12 September 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/BoxCox.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.analysis; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.*; +import java.text.*; + +import flanagan.analysis.Stat; +import flanagan.analysis.Regression; +import flanagan.math.ArrayMaths; +import flanagan.math.Maximization; +import flanagan.math.MaximizationFunction; +import flanagan.math.Fmath; +import flanagan.plot.*; +import flanagan.io.FileOutput; + + + +public class BoxCox{ + + private double[] originalData = null; // original data to be analysed as Gaussian + private double[] sortedOriginalData = null; // ordered original data + private double[] standardizedOriginalData = null; // standardized original data + private Stat sod = null; // Stat instance of the standardizedOriginalData + private double[] shiftedStandardizedOriginalData = null; // data shifted to ensure all points are positive + private int[] originalIndices = null; // original indices before data are ordered into ascending order + private int nData = 0; // number of data points + + private double originalRange = 0.0; // original data range + private double originalMinimum = 0.0; // original data minimum + private double originalMaximum = 0.0; // original data maximum + private double originalMean = 0.0; // original data mean + private double originalMedian = 0.0; // original original data median + private double originalStandardDeviation = 0.0; // original data standard deviation + private double originalVariance = 0.0; // original data variance + private double originalMomentSkewness = 0.0; // original data moment skewness + private double originalMedianSkewness = 0.0; // original data median skewness + private double originalQuartileSkewness = 0.0; // original data quartile skewness + private double originalExcessKurtosis = 0.0; // original data excess kurtosis + + private double standardizedOriginalRange = 0.0; // standardized original data range + private double standardizedOriginalMinimum = 0.0; // standardized original data minimum + private double standardizedOriginalMaximum = 0.0; // standardized original data maximum + private double standardizedOriginalMean = 0.0; // standardized original original data mean + private double standardizedOriginalMedian = 0.0; // standardized original original data median + private double standardizedOriginalStandardDeviation = 1.0; // standardized original data standard deviation + private double standardizedOriginalVariance = 1.0; // standardized original data variance + private double standardizedOriginalMomentSkewness = 0.0; // standardized original data moment skewness + private double standardizedOriginalMedianSkewness = 0.0; // standardized original data median skewness + private double standardizedOriginalQuartileSkewness = 0.0; // standardized original data quartile skewness + private double standardizedOriginalExcessKurtosis = 0.0; // standardized original data excess kurtosis + + private double originalSampleR = 0.0; // Probabilty plot correlation coefficient for the original data + private double originalIntercept = 0.0; // Probabilty plot intercept for the original data + private double originalGradient = 0.0; // Probabilty plot gradient for the original data + + private double[] transformedData = null; // Box-Cox transformed data + private double[] standardizedTransformedData = null; // standardized Box-Cox transformed data + private double[] scaledTransformedData = null; // Box-Cox transformed data scaled to original mean and standard deviation + private double[] sortedScaledTransformedData = null; // Box-Cox transformed data scaled to original mean and standard deviation sorted into ascending order + + private double transformedRange = 0.0; // scaled transformed data range + private double transformedMinimum = 0.0; // scaled transformed data minimum + private double transformedMaximum = 0.0; // scaled transformed data maximum + private double transformedMean = 0.0; // scaled transformed data mean + private double transformedStandardDeviation = 0.0; // scaled transformed data standard deviation + private double transformedMedian = 0.0; // scaled transformed data median + private double transformedVariance = 0.0; // scaled transformed data variance + private double transformedMomentSkewness = 0.0; // scaled transformed data moment skewness + private double transformedMedianSkewness = 0.0; // scaled transformed data median skewness + private double transformedQuartileSkewness = 0.0; // scaled transformed data quartile skewness + private double transformedExcessKurtosis = 0.0; // scaled transformed data excess kurtosis + + private double standardizedTransformedRange = 0.0; // standardized transformed data range + private double standardizedTransformedMinimum = 0.0; // standardized transformed data minimum + private double standardizedTransformedMaximum = 0.0; // standardized transformed data maximum + private double standardizedTransformedMean = 0.0; // standardized transformed data mean + private double standardizedTransformedMedian = 0.0; // standardized transformed data median + private double standardizedTransformedStandardDeviation = 1.0; // standardized transformed data standard deviation + private double standardizedTransformedVariance = 1.0; // standardized transformed data variance + private double standardizedTransformedMomentSkewness = 0.0; // standardized transformed data moment skewness + private double standardizedTransformedMedianSkewness = 0.0; // standardized transformed data median skewness + private double standardizedTransformedQuartileSkewness = 0.0; // standardized transformed data quartile skewness + private double standardizedTransformedExcessKurtosis = 0.0; // standardized transformed data excess kurtosis + + + private double lambdaOne = 0.0; // Box-Cox lambdaOne + private double lambdaTwo = 0.0; // Box-Cox lambdaTwo + + private double transformedSampleR = 0.0; // Probabilty plot correlation coefficient for the transformed data + private double transformedIntercept = 0.0; // Probabilty plot intercept for the transformed data + private double transformedGradient = 0.0; // Probabilty plot gradient for the transformed data + + private double[] uniformOrderMedians = null; // uniform order statistic medians + private double[] gaussianOrderMedians = null; // Gaussian order statistic medians + + private boolean transformDone = false; // = true when Box-Cox transform performed + + + + // CONSTRUCTORS + public BoxCox(double[] originalData){ + this.sod = new Stat(originalData); + } + + public BoxCox(float[] originalData){ + this.sod = new Stat(originalData); + } + + public BoxCox(int[] originalData){ + this.sod = new Stat(originalData); + } + + public BoxCox(long[] originalData){ + this.sod = new Stat(originalData); + } + + public BoxCox(short[] originalData){ + this.sod = new Stat(originalData); + } + + public BoxCox(byte[] originalData){ + this.sod = new Stat(originalData); + } + + public BoxCox(BigDecimal[] originalData){ + this.sod = new Stat(originalData); + } + + public BoxCox(BigInteger[] originalData){ + this.sod = new Stat(originalData); + } + + public BoxCox(Stat originalData){ + this.sod = originalData; + } + + public BoxCox(ArrayMaths amoriginalData){ + this.sod = amoriginalData.toStat(); + } + + public BoxCox(ArrayList<Object> originalData){ + this.sod = new Stat(originalData); + } + + public BoxCox(Vector<Object> originalData){ + this.sod = new Stat(originalData); + } + + // set denominator of variances to n + public void setDenominatorToN(){ + Stat.setStaticDenominatorToN(); + } + + // Initialise original data arrays + private void initialize(){ + + // store entered data as instance variable + this.originalData = this.sod.array_as_double(); + + // Calculate original data statistics + this.originalMinimum = this.sod.minimum(); + this.originalMaximum = this.sod.maximum(); + this.originalMedian = this.sod.median(); + if(this.originalMinimum==this.originalMaximum)throw new IllegalArgumentException("A Box-Cox transformation cannot be performed on a data array of identical values"); + this.originalRange = this.originalMaximum - this.originalMinimum; + this.originalMean = this.sod.mean(); + this.originalStandardDeviation = this.sod.standardDeviation(); + this.originalVariance = this.sod.variance(); + this.originalMomentSkewness = this.sod.momentSkewness(); + this.originalMedianSkewness = this.sod.medianSkewness(); + this.originalQuartileSkewness = this.sod.quartileSkewness(); + this.originalExcessKurtosis = this.sod.excessKurtosis(); + + // Store original data sorted into ascending order + Stat sorted = this.sod.sort(); + this.sortedOriginalData = sorted.array(); + this.originalIndices = sorted.originalIndices(); + + // Standardize and store standardized data + this.standardizedOriginalData = this.sod.standardize(); + + // Calculate standardized original data statistics + this.standardizedOriginalMinimum = this.sod.minimum(); + this.standardizedOriginalMaximum = this.sod.maximum(); + this.standardizedOriginalMedian = this.sod.median(); + this.standardizedOriginalRange = this.standardizedOriginalMaximum - this.standardizedOriginalMinimum; + this.standardizedOriginalMean = 0.0; + this.standardizedOriginalStandardDeviation = 1.0; + this.standardizedOriginalVariance = 1.0; + this.standardizedOriginalMomentSkewness = this.sod.momentSkewness(); + this.standardizedOriginalMedianSkewness = this.sod.medianSkewness(); + this.standardizedOriginalQuartileSkewness = this.sod.quartileSkewness(); + this.standardizedOriginalExcessKurtosis = this.sod.excessKurtosis(); + + // Numbet of data points + this.nData = this.originalData.length; + + // Calculate uniform order statistic medians + this.uniformOrderMedians = Stat.uniformOrderStatisticMedians(this.nData); + + // Calculate Gaussian N[0,1] order statistic medians + this.gaussianOrderMedians = Stat.gaussianOrderStatisticMedians(this.nData); + + // calculate the correlation coefficient of the probability plot for the untransformed data + Regression reg = new Regression(this.gaussianOrderMedians, ((new ArrayMaths(this.standardizedOriginalData)).sort().array())); + reg.linear(); + this.originalSampleR = reg.getSampleR(); + double[] coeff = reg.getBestEstimates(); + this.originalIntercept = coeff[0]; + this.originalGradient = coeff[1]; + } + + // BOX-COX TRANSFORMATION + private double[] transform(){ + if(this.originalData==null)throw new IllegalArgumentException("No data has been entered (via a constructor)"); + + // initialize arrays and analyse original data + this.initialize(); + + // Shift data to ensure all values are greater than zero + this.lambdaTwo = 0.1*this.standardizedOriginalRange - this.standardizedOriginalMinimum; + Stat st1 = this.sod.plus(this.lambdaTwo); + this.shiftedStandardizedOriginalData = st1.getArray_as_double(); + + // Create an instance of the BoxCoxFunction for Maximization + BoxCoxFunction bcf = new BoxCoxFunction(); + bcf.shiftedData = this.shiftedStandardizedOriginalData; + bcf.nData = this.nData; + bcf.yTransform = new double[this.nData]; + bcf.gaussianOrderMedians = this.gaussianOrderMedians; + + // Create an instance of Maximization + Maximization max = new Maximization(); + + // Initial estimate of lambdaOne + double[] start = {1.0}; + + // Initial step size in maximization search + double[] step = {0.3}; + + // Tolerance for maximization search termination + double maxzTol = 1e-9; + + // Maximiztaion of the Gaussian probabilty plot correlation coefficient varying lambdaOne + max.nelderMead(bcf, start, step, maxzTol); + + // coeff[0] = value of lambdaOne for a maximum Gaussian probabilty plot correlation coefficient + double[] coeff = max.getParamValues(); + double lambda1 = coeff[0]; + + //maximum Gaussian probabilty plot correlation coefficient + double sampleR1 = max.getMaximum(); + + // Repeat maximization starting equidistant from the final value of lambdaOne on the opposite side from the starting estimate + start[0] = lambda1 - (start[0] - lambda1); + max.nelderMead(bcf, start, step, maxzTol); + coeff = max.getParamValues(); + this.lambdaOne = coeff[0]; + this.transformedSampleR = max.getMaximum(); + + // Choose solution with the largest Gaussian probabilty plot correlation coefficient + if(sampleR1>this.transformedSampleR){ + this.transformedSampleR = sampleR1; + this.lambdaOne = lambda1; + } + + // Store transformed data + this.transformedData = new double[this.nData]; + for(int i=0; i<this.nData; i++){ + this.transformedData[i] = (Math.pow(this.shiftedStandardizedOriginalData[i], this.lambdaOne) - 1.0)/this.lambdaOne; + } + + // Standardize transformed data + this.standardizedTransformedData = (new Stat(this.transformedData)).standardize(); + + // Calculate standardized transformed data statistics + Stat st3 = new Stat(this.transformedData); + this.standardizedTransformedMinimum = st3.minimum(); + this.standardizedTransformedMaximum = st3.maximum(); + this.standardizedTransformedMedian = st3.median(); + this.standardizedTransformedRange = this.standardizedTransformedMaximum - this.standardizedTransformedMinimum; + this.standardizedTransformedMean = 0.0; + this.standardizedTransformedStandardDeviation = 1.0; + this.standardizedTransformedVariance = 1.0; + this.standardizedTransformedMomentSkewness = st3.momentSkewness(); + this.standardizedTransformedMedianSkewness = st3.medianSkewness(); + this.standardizedTransformedQuartileSkewness = st3.quartileSkewness(); + this.standardizedTransformedExcessKurtosis = st3.excessKurtosis(); + + // Obtain the intercept and gradient of the Gaussian probabilty plot + Stat st4 = new Stat(this.standardizedTransformedData); + st4 = st4.sort(); + double[] ordered = st4.array(); + Regression reg = new Regression(this.gaussianOrderMedians, ordered); + reg.linear(); + coeff = reg.getBestEstimates(); + this.transformedIntercept = coeff[0]; + this.transformedGradient = coeff[1]; + + // Adust mean and standard deviation of the transformed data to match those of the entered data + this.scaledTransformedData = Stat.scale(this.standardizedTransformedData, this.originalMean, this.originalStandardDeviation); + + // Calculate transformed data statistics + Stat st2 = new Stat(scaledTransformedData); + this.transformedMinimum = st2.minimum(); + this.transformedMaximum = st2.maximum(); + this.transformedMedian = st2.median(); + this.transformedRange = this.transformedMaximum - this.transformedMinimum; + this.transformedMean = st2.mean(); + this.transformedStandardDeviation = st2.standardDeviation(); + this.transformedVariance = st2.variance(); + this.transformedMomentSkewness = st2.momentSkewness(); + this.transformedMedianSkewness = st2.medianSkewness(); + this.transformedQuartileSkewness = st2.quartileSkewness(); + this.transformedExcessKurtosis = st2.excessKurtosis(); + + // Arrange scaled transformed data into ascending order + Stat st5 = new Stat(this.scaledTransformedData); + this.sortedScaledTransformedData = (st5.sort()).array(); + + // end of method and return transformed data + this.transformDone = true; + return this.transformedData; + + } + + // RETURN RESULTS + // Return lambdaOne + public double lambdaOne(){ + if(!this.transformDone)this.transform(); + return this.lambdaOne; + } + + // Return lambdaTwo + public double lambdaTwo(){ + if(!this.transformDone)this.transform(); + return this.lambdaTwo; + } + + // Return Gaussian probabilty plot correlation coefficient of the transformed data + public double transformedCorrelationCoefficient(){ + if(!this.transformDone)this.transform(); + return this.transformedSampleR; + } + + // Return Gaussian probabilty plot gradient of the transformed data + public double transformedGradient(){ + if(!this.transformDone)this.transform(); + return this.transformedGradient; + } + + // Return Gaussian probabilty plot intercept of the transformed data + public double transformedIntercept(){ + if(!this.transformDone)this.transform(); + return this.transformedIntercept; + } + + // Return Gaussian probabilty plot correlation coefficient of the original data + public double originalCorrelationCoefficient(){ + if(!this.transformDone)this.transform(); + return this.originalSampleR; + } + + // Return Gaussian probabilty plot gradient of the orioginal data + public double originalGradient(){ + if(!this.transformDone)this.transform(); + return this.originalGradient; + } + + // Return Gaussian probabilty plot intercept of the original data + public double originalIntercept(){ + if(!this.transformDone)this.transform(); + return this.originalIntercept; + } + + // Return original data + public double[] originalData(){ + if(!this.transformDone)this.transform(); + return this.originalData; + } + + // Return standardized original data + public double[] standardizedOriginalData(){ + if(!this.transformDone)this.transform(); + return this.standardizedOriginalData; + } + + // Return ordered original data + public double[] sortedOriginalData(){ + if(!this.transformDone)this.transform(); + return this.sortedOriginalData; + } + + // Return shifted standardized original data + public double[] shiftedStandardizedOriginalata(){ + if(!this.transformDone)this.transform(); + return this.shiftedStandardizedOriginalData; + } + + // Return transformed data + public double[] transformedData(){ + if(!this.transformDone)this.transform(); + return this.transformedData; + } + + // Return scaled transformed data + public double[] scaledTransformedData(){ + if(!this.transformDone)this.transform(); + return this.scaledTransformedData; + } + + // Return standardized transformed data + public double[] standardizedTransformedData(){ + if(!this.transformDone)this.transform(); + return this.standardizedTransformedData; + } + + // Return ordered transformed data + public double[] orderedTransformedData(){ + if(!this.transformDone)this.transform(); + ArrayMaths am = new ArrayMaths(this.transformedData); + double[] ordered = (am.sort()).array(); + return ordered; + } + + // Return ordered scaled transformed data + public double[] orderedScaledTransformedData(){ + if(!this.transformDone)this.transform(); + return this.sortedScaledTransformedData; + + } + + // Return original data mean + public double originalMean(){ + if(!this.transformDone)this.transform(); + return this.originalMean; + } + + // Return original data median + public double originalMedian(){ + if(!this.transformDone)this.transform(); + return this.originalMedian; + } + + // Return original data standard deviation + public double originalStandardDeviation(){ + if(!this.transformDone)this.transform(); + return this.originalStandardDeviation; + } + + // Return original data standard error of the mean + public double originalStandardError(){ + return this.originalStandardDeviation/Math.sqrt(this.nData); + } + + // Return original data variance + public double originalVariance(){ + if(!this.transformDone)this.transform(); + return this.originalVariance; + } + + // Return original data moment skewness + public double originalMomentSkewness(){ + if(!this.transformDone)this.transform(); + return this.originalMomentSkewness; + } + + // Return original data median skewness + public double originalMedianSkewness(){ + if(!this.transformDone)this.transform(); + return this.originalMedianSkewness; + } + + // Return original data quartile skewness + public double originalQuartiletSkewness(){ + if(!this.transformDone)this.transform(); + return this.originalQuartileSkewness; + } + + // Return original data excess kurtosis + public double originalExcessKurtosis(){ + if(!this.transformDone)this.transform(); + return this.originalExcessKurtosis; + } + + // Return original data maximum + public double originalMaximum(){ + if(!this.transformDone)this.transform(); + return this.originalMaximum; + } + + // Return original data minimum + public double originalMinimum(){ + if(!this.transformDone)this.transform(); + return this.originalMinimum; + } + + // Return original data range + public double originalRange(){ + if(!this.transformDone)this.transform(); + return this.originalRange; + } + + + // Return transformed data mean + public double transformedMean(){ + if(!this.transformDone)this.transform(); + return this.transformedMean; + } + + // Return transformed data median + public double transformedMedian(){ + if(!this.transformDone)this.transform(); + return this.transformedMedian; + } + + + // Return transformed data standard deviation + public double transformedStandardDeviation(){ + if(!this.transformDone)this.transform(); + return this.transformedStandardDeviation; + } + + // Return transformed data standard error of the mean + public double transformedStandardError(){ + if(!this.transformDone)this.transform(); + return this.transformedStandardDeviation/Math.sqrt(this.nData); + } + + // Return transformed data variance + public double transformedVariance(){ + if(!this.transformDone)this.transform(); + return this.transformedVariance; + } + + // Return transformed data moment skewness + public double transformedMomentSkewness(){ + if(!this.transformDone)this.transform(); + return this.transformedMomentSkewness; + } + + // Return transformed data median skewness + public double transformedMedianSkewness(){ + if(!this.transformDone)this.transform(); + return this.transformedMedianSkewness; + } + + // Return transformed data quartile skewness + public double transformedQuartileSkewness(){ + if(!this.transformDone)this.transform(); + return this.transformedQuartileSkewness; + } + + // Return transformed data excess kurtosis + public double transformedExcessKurtosis(){ + if(!this.transformDone)this.transform(); + return this.transformedExcessKurtosis; + } + + // Return transformed data maximum + public double transformedMaximum(){ + if(!this.transformDone)this.transform(); + return this.transformedMaximum; + } + + // Return transformed data minimum + public double transformedMinimum(){ + if(!this.transformDone)this.transform(); + return this.transformedMinimum; + } + + // Return transformed data range + public double transformedRange(){ + if(!this.transformDone)this.transform(); + return this.transformedRange; + } + + // PLOTS + // Gaussian probabilty plot of the standardized transformed data + public void transformedProbabilityPlot(){ + if(!this.transformDone)this.transform(); + + double[][] data = PlotGraph.data(2,this.nData); + data[0] = this.gaussianOrderMedians; + data[1] = ((new ArrayMaths(this.standardizedTransformedData)).sort()).array(); + + data[2] = this.gaussianOrderMedians; + for(int i=0; i<this.nData; i++){ + data[3][i] = this.transformedIntercept + this.transformedGradient*this.gaussianOrderMedians[i]; + } + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("Gaussian [0,1] Order Statistic Medians"); + pg.setYaxisLegend("Ordered Response Values"); + String legend1 = "Gausssian probability plot: Box-Cox transformed data"; + String legend2 = "lambdaOne = " + Fmath.truncate(this.lambdaOne, 4) + ", lambdaTwo = " + Fmath.truncate(this.lambdaTwo, 4) + ", gradient = " + Fmath.truncate(this.transformedGradient, 4) + ", intercept = " + Fmath.truncate(this.transformedIntercept, 4) + ", R = " + Fmath.truncate(this.transformedSampleR, 4); + pg.setGraphTitle(legend1); + pg.setGraphTitle2(legend2); + pg.plot(); + } + + // Gaussian probabilty plot of the standardized original data + public void originalProbabilityPlot(){ + double[][] data = PlotGraph.data(2,this.nData); + data[0] = this.gaussianOrderMedians; + data[1] = ((new ArrayMaths(this.standardizedOriginalData)).sort()).array(); + data[2] = this.gaussianOrderMedians; + for(int i=0; i<this.nData; i++){ + data[3][i] = this.originalIntercept + this.originalGradient*this.gaussianOrderMedians[i]; + } + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("Gaussian [0,1] Order Statistic Medians"); + pg.setYaxisLegend("Ordered Response Values"); + String legend1 = "Gausssian probability plot: original data for a Box-Cox transformation"; + String legend2 = "gradient = " + Fmath.truncate(this.originalGradient, 4) + ", intercept = " + Fmath.truncate(this.originalIntercept, 4) + ", R = " + Fmath.truncate(this.originalSampleR, 4); + pg.setGraphTitle(legend1); + pg.setGraphTitle2(legend2); + pg.plot(); + } + + // Output analysis to text + public void analysis(){ + this.analysis("BoxCoxAnalysis.txt"); + } + + public void analysis(String title){ + if(!this.transformDone)this.transform(); + + this.originalProbabilityPlot(); + this.transformedProbabilityPlot(); + + int posdot = title.indexOf("."); + if(posdot==-1)title = title + ".txt"; + + FileOutput fout = new FileOutput(title); + fout.println("Box-Cox Analysis"); + fout.println("File name: " + title); + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + fout.println("Program executed at " + tim + " on " + day); + fout.println(); + + int field1 = 30; + int field2 = 15; + fout.print("Box-Cox lambda one", field1); + fout.println(Fmath.truncate(this.lambdaOne, 4)); + fout.print("Box-Cox lambda two", field1); + fout.println(Fmath.truncate(this.lambdaTwo, 4)); + fout.println(); + + fout.print(" ", field1); + fout.print("Transformed", field2); + fout.println("Original "); + fout.print(" ", field1); + fout.print("scaled data", field2); + fout.println("data "); + + fout.println("Gaussian Probability plot "); + fout.print(" Correlation coefficient", field1); + fout.print(Fmath.truncate(this.transformedSampleR, 4), field2); + fout.println(Fmath.truncate(this.originalSampleR, 4)); + + fout.print(" Gradient", field1); + fout.print(Fmath.truncate(this.transformedGradient, 4), field2); + fout.println(Fmath.truncate(this.originalGradient, 4)); + + fout.print(" Intercept", field1); + fout.print(Fmath.truncate(this.transformedIntercept, 4), field2); + fout.println(Fmath.truncate(this.originalIntercept, 4)); + fout.println(); + + fout.print("Data "); + fout.println(); + fout.print("Mean", field1); + fout.print(Fmath.truncate(this.transformedMean, 4), field2); + fout.println(Fmath.truncate(this.originalMean, 4)); + + fout.print("Median", field1); + fout.print(Fmath.truncate(this.transformedMedian, 4), field2); + fout.println(Fmath.truncate(this.originalMedian, 4)); + + fout.print("Standard deviation", field1); + fout.print(Fmath.truncate(this.transformedStandardDeviation, 4), field2); + fout.println(Fmath.truncate(this.originalStandardDeviation, 4)); + + fout.print("Standard error", field1); + fout.print(Fmath.truncate(this.transformedStandardDeviation/Math.sqrt(this.nData), 4), field2); + fout.println(Fmath.truncate(this.originalStandardDeviation/Math.sqrt(this.nData), 4)); + + fout.print("Moment skewness", field1); + fout.print(Fmath.truncate(this.transformedMomentSkewness, 4), field2); + fout.println(Fmath.truncate(this.originalMomentSkewness, 4)); + + fout.print("Median skewness", field1); + fout.print(Fmath.truncate(this.transformedMedianSkewness, 4), field2); + fout.println(Fmath.truncate(this.originalMedianSkewness, 4)); + + fout.print("Quartile skewness", field1); + fout.print(Fmath.truncate(this.transformedQuartileSkewness, 4), field2); + fout.println(Fmath.truncate(this.originalQuartileSkewness, 4)); + + fout.print("Excess kurtosis", field1); + fout.print(Fmath.truncate(this.transformedExcessKurtosis, 4), field2); + fout.println(Fmath.truncate(this.originalExcessKurtosis, 4)); + + fout.print("Minimum", field1); + fout.print(Fmath.truncate(this.transformedMinimum, 4), field2); + fout.println(Fmath.truncate(this.originalMinimum, 4)); + + fout.print("Maximum", field1); + fout.print(Fmath.truncate(this.transformedMaximum, 4), field2); + fout.println(Fmath.truncate(this.originalMaximum, 4)); + + fout.print("Range", field1); + fout.print(Fmath.truncate(this.transformedRange, 4), field2); + fout.println(Fmath.truncate(this.originalRange, 4)); + + fout.close(); + } + +} + +// Function for Box-Cox transform maximization +class BoxCoxFunction implements MaximizationFunction{ + + public double[] shiftedData = null; + public int nData = 0; + public double[] yTransform = null; + public double[] gaussianOrderMedians = null; + public Regression reg = null; + public ArrayMaths am = null; + + public double function( double[] x){ + + // Box-Cox transform + for(int i=0; i<nData; i++){ + if(x[0]==0){ + yTransform[i] = Math.log(shiftedData[i]); + } + else{ + yTransform[i] = (Math.pow(shiftedData[i], x[0]) - 1.0)/x[0]; + } + } + + // Sort transformed array into ascending order + am = new ArrayMaths(yTransform); + am = am.sort(); + yTransform = am.array(); + + // Calculate and return probability plot correlation coefficient + reg = new Regression(gaussianOrderMedians, yTransform); + reg.linear(); + return reg.getSampleR(); + + } + +} \ No newline at end of file diff --git a/src/main/java/flanagan/analysis/Cronbach.java b/src/main/java/flanagan/analysis/Cronbach.java new file mode 100755 index 0000000000000000000000000000000000000000..9d82f4a5641616ff9f4a1b60bda218c0481ab566 --- /dev/null +++ b/src/main/java/flanagan/analysis/Cronbach.java @@ -0,0 +1,1739 @@ +/* +* CLASS: Cronbach +* +* USAGE: Cronbach raw data alpha reliability +* Cronbach standardized data alpha reliability +* Correlation between items +* Deletion of items +* +* This is a subclass of the superclass Scores +* +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: July and Agust 2008 +* AMENDED: 22 August 2008, 29 August 2008, 1-8 October 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* http://www.ee.ucl.ac.uk/~mflanaga/java/Cronbach.html +* +* Copyright (c) 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + + +package flanagan.analysis; + +import java.util.*; +import java.text.*; + +import flanagan.math.*; +import flanagan.io.*; +import flanagan.analysis.*; +import flanagan.plot.*; + + +public class Cronbach extends Scores{ + + private double rawAlpha = Double.NaN; // Cronbach raw data alpha reliability coefficient + private boolean rawAlphaCalculated = false; // = true when raw data alpha reliability coefficient calculated + private double standardizedAlpha = Double.NaN; // Cronbach standardized data alpha reliability coefficient + private boolean standardizedAlphaCalculated = false; // = true when standardized alpha reliability coefficient calculated + + private int deletedItemIndex = -1; // the index of the least consistent item + + + + // CONSTRUCTOR + public Cronbach(){ + } + + // CRONBACH RAW DATA ALPHA + public double rawAlpha(){ + + if(!this.rawAlphaCalculated){ + + if(this.nItems==1){ + System.out.println("Method rawAlpha: only one item - alpha cannot be calculated - NaN returned"); + this.rawAlpha = Double.NaN; + } + else{ + + // Check that data is preprocessed + if(!this.dataPreprocessed)this.preprocessData(); + + // (Sum of scores1) squared + double rawAllResponsesTotalAllSquared = this.rawAllResponsesTotal*this.rawAllResponsesTotal; + + // Sum of (scores1 squared) + double sumOfEachScoreSquared = 0.0; + for(int i=0;i<this.nItems;i++){ + for(int j=0;j<this.nPersons;j++)sumOfEachScoreSquared += scores1[j][i]*scores1[j][i]; + } + + + // Reduced sum of column totals squared + double reducedItemTotalsSquared = 0.0; + for(int i=0;i<this.nItems;i++)reducedItemTotalsSquared += rawItemTotals[i]*rawItemTotals[i]/this.nPersons; + + // Reduced sum of row totals squared + double reducedPersonTotalsSquared = 0.0; + for(int i=0;i<this.nPersons;i++)reducedPersonTotalsSquared += rawPersonTotals[i]*rawPersonTotals[i]/this.nItems; + + //Sum of squares within persons + double sumOfSquaresWithinPersons = reducedPersonTotalsSquared - rawAllResponsesTotalAllSquared/this.nScores; + + //Sum of square errors + double sumOfSquareErrors = sumOfEachScoreSquared - reducedItemTotalsSquared - reducedPersonTotalsSquared + rawAllResponsesTotalAllSquared/this.nScores; + + //Degrees of freedom + //iiems + int dfItems = this.nItems- 1; + //persons + int dfPersons = this.nPersons - 1; + // errors + int dfErrors = dfItems*dfPersons; + + // Mean Squares + double reducedSquarePersons = sumOfSquaresWithinPersons/dfPersons; + double reducedSquareErrors = sumOfSquareErrors/dfErrors; + + // Cronbach raw alpha reliability coefficient + this.rawAlpha = (reducedSquarePersons - reducedSquareErrors)/reducedSquarePersons; + this.rawAlphaCalculated = true; + } + } + return this.rawAlpha; + } + + + + // CRONBACH STANDARDIZED DATA ALPHA + public double standardizedAlpha(){ + + if(!this.standardizedAlphaCalculated){ + + if(this.nItems==1){ + System.out.println("Method standardizedAlpha: only one item - alpha cannot be calculated - NaN returned"); + this.rawAlpha = Double.NaN; + } + else{ + + // Check that data is preprocessed + if(!this.dataPreprocessed)this.preprocessData(); + + // Calculate correlation coefficients + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + + // Cronbach standardized alpha reliability coefficient + this.standardizedAlpha = this.nItems*this.rawMeanRhoWithoutTotals/(1.0 + (this.nItems - 1)*this.rawMeanRhoWithoutTotals); + this.standardizedAlphaCalculated = true; + } + } + + return this.standardizedAlpha; + } + + public double standardisedAlpha(){ + return this.standardizedAlpha(); + } + + + + + + // OUTPUT THE ANALYSIS + + // Full analysis without output of input data + // no input file name entered via method argument list + public void analysis(){ + + this.outputFilename = "CronbachOutput"; + if(this.fileOption==1){ + this.outputFilename += ".txt"; + } + else{ + this.outputFilename += ".xls"; + } + String message1 = "Output file name for the analysis details:"; + String message2 = "\nEnter the required name (as a single word) and click OK "; + String message3 = "\nor simply click OK for default value"; + String message = message1 + message2 + message3; + String defaultName = this.outputFilename; + this.outputFilename = Db.readLine(message, defaultName); + this.analysis(this.outputFilename); + } + + // Full analysis without output of input data + // input file name via method argument list + public void analysis(String filename){ + // Open output file + this.outputFilename = filename; + String outputFilenameWithoutExtension = null; + String extension = null; + int pos = filename.indexOf('.'); + if(pos==-1){ + outputFilenameWithoutExtension = filename; + if(this.fileOption==1){ + this.outputFilename += ".txt"; + } + else{ + this.outputFilename += ".xls"; + } + } + else{ + extension = (filename.substring(pos)).trim(); + + outputFilenameWithoutExtension = (filename.substring(0, pos)).trim(); + if(extension.equalsIgnoreCase(".xls")){ + if(this.fileOption==1){ + if(this.fileOptionSet){ + String message1 = "Your entered output file type is .xls"; + String message2 = "\nbut you have chosen a .txt output"; + String message = message1 + message2; + String headerComment = "Your output file name extension"; + String[] comments = {message, "replace it with .txt [text file]"}; + String[] boxTitles = {"Retain", ".txt"}; + int defaultBox = 1; + int opt = Db.optionBox(headerComment, comments, boxTitles, defaultBox); + if(opt==2)this.outputFilename = outputFilenameWithoutExtension + ".txt"; + } + else{ + this.fileOption=2; + } + } + } + + if(extension.equalsIgnoreCase(".txt")){ + if(this.fileOption==2){ + if(this.fileOptionSet){ + String message1 = "Your entered output file type is .txt"; + String message2 = "\nbut you have chosen a .xls output"; + String message = message1 + message2; + String headerComment = "Your output file name extension"; + String[] comments = {message, "replace it with .xls [Excel file]"}; + String[] boxTitles = {"Retain", ".xls"}; + int defaultBox = 1; + int opt = Db.optionBox(headerComment, comments, boxTitles, defaultBox); + if(opt==2)this.outputFilename = outputFilenameWithoutExtension + ".xls"; + } + else{ + this.fileOption=1; + } + } + } + + if(!extension.equalsIgnoreCase(".txt") && !extension.equalsIgnoreCase(".xls")){ + String message1 = "Your extension is " + extension; + String message2 = "\n Do you wish to retain it:"; + String message = message1 + message2; + String headerComment = "Your output file name extension"; + String[] comments = {message, "replace it with .txt [text file]", "replace it with .xls [MS Excel file]"}; + String[] boxTitles = {"Retain", ".txt", ".xls"}; + int defaultBox = 1; + int opt = Db.optionBox(headerComment, comments, boxTitles, defaultBox); + switch(opt){ + case 1: this.fileOption=1; + break; + case 2: this.outputFilename = outputFilenameWithoutExtension + ".txt"; + this.fileOption=1; + break; + case 3: this.outputFilename = outputFilenameWithoutExtension + ".xls"; + this.fileOption=2; + break; + } + } + } + + if(this.fileOption==1){ + this.analysisText(); + } + else{ + this.analysisExcel(); + } + } + + private void analysisExcel(){ + + FileOutput fout = null; + if(this.fileNumberingSet){ + fout = new FileOutput(this.outputFilename, 'n'); + } + else{ + fout = new FileOutput(this.outputFilename); + } + + // calculate alphas if not already calculated + if(!rawAlphaCalculated)this.rawAlpha(); + if(!standardizedAlphaCalculated)this.standardizedAlpha(); + + // output title information + + fout.println("CRONBACH'S ALPHA RELIABILITY ESTIMATOR"); + fout.println("Program: Cronbach - Analysis Output"); + for(int i=0; i<this.titleLines; i++)fout.println(title[i]); + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + fout.println("Program executed at " + tim + " on " + day); + fout.println(); + + // output reliability estimators + fout.println("RELIABILITY ESTIMATORS"); + fout.println("Cronbach's coefficient alpha"); + fout.printtab("Raw data "); + fout.println(Fmath.truncate(this.rawAlpha, this.trunc)); + fout.printtab("Standardized data "); + fout.println(Fmath.truncate(this.standardizedAlpha, this.trunc)); + fout.println(); + + fout.println("Average of the inter-item correlation coefficients, excluding item totals"); + fout.printtab("Raw data "); + fout.println(Fmath.truncate(this.rawMeanRhoWithoutTotals, this.trunc)); + fout.printtab("Standardized data "); + fout.println(Fmath.truncate(this.standardizedMeanRhoWithoutTotals, this.trunc)); + fout.println(); + + fout.println("Average of the inter-item correlation coefficients, including item totals"); + fout.printtab("Raw data "); + fout.println(Fmath.truncate(this.rawMeanRhoWithTotals, this.trunc)); + fout.printtab("Standardized data "); + fout.println(Fmath.truncate(this.standardizedMeanRhoWithTotals, this.trunc)); + fout.println(); + + // output any deletions or replacements + fout.println("'NO RESPONSE' DELETIONS AND REPLACEMENTS"); + // deleted persons + boolean deletionFlag = false; + if(this.nDeletedPersons!=0){ + deletionFlag = true; + fout.printtab("Number of persons deleted "); + fout.println(this.nDeletedPersons); + fout.printtab("Indices of deleted persons: "); + for(int i=0; i<this.nDeletedPersons; i++)fout.printtab(this.deletedPersonsIndices[i]+1); + fout.println(); + } + else{ + fout.println("No persons were deleted "); + } + + // deleted items + if(this.nDeletedItems!=0){ + deletionFlag = true; + fout.printtab("Number of items deleted "); + fout.println(this.nDeletedItems); + fout.printtab("Names of deleted items: "); + for(int i=0; i<this.nDeletedItems; i++)fout.printtab(this.originalItemNames[this.deletedItemsIndices[i]]); + fout.println(); + } + else{ + fout.println("No items were deleted "); + } + + // replacements + if(this.nReplacements!=0){ + fout.printtab("Number of 'no responses' replaced "); + fout.println(this.nReplacements); + fout.printtab("Item name and person index of replacements: "); + for(int i=0; i<this.nReplacements; i++)fout.printtab(this.replacementIndices[i]); + fout.printtab("Replacement option: "); + fout.println(this.replacementOptionNames[this.replacementOption-1]); + fout.println(); + } + else{ + if(deletionFlag){ + fout.println("No 'no response' replacements, other than any above deletions, were made "); + } + else{ + fout.println("No 'no response' replacements were made "); + } + } + fout.println(); + fout.printtab("Number of items used "); + fout.println(this.nItems); + fout.printtab("Number of persons used "); + fout.println(this.nPersons); + fout.println(); + + // Correlation coefficients + fout.println("CORRELATION COEFFICIENTS"); + fout.println("Correlation coefficients between items - raw data"); + fout.printtab(" "); + for(int i=0; i<=this.nItems; i++)fout.printtab(this.itemNames[i]); + fout.println(); + for(int i=0; i<=this.nItems; i++){ + fout.printtab(this.itemNames[i]); + for(int j=0; j<=this.nItems; j++)fout.printtab(Fmath.truncate(this.rawCorrelationCoefficients[i][j], this.trunc)); + fout.println(); + } + fout.println(); + + fout.print("Average inter-item correlation coefficient (excluding total) "); + fout.println(Fmath.truncate(this.rawMeanRhoWithoutTotals, this.trunc)); + fout.print("Standard deviation of the inter-item correlation coefficient (excluding total) "); + fout.println(Fmath.truncate(this.rawStandardDeviationRhoWithoutTotals, this.trunc)); + fout.print("Average inter-item correlation coefficient (including total) "); + fout.println(Fmath.truncate(this.rawMeanRhoWithTotals, this.trunc)); + fout.print("Standard deviation of the inter-item correlation coefficient (including total) "); + fout.println(Fmath.truncate(this.rawStandardDeviationRhoWithTotals, this.trunc)); + fout.println(); + + + fout.println("Correlation coefficients between items - standardized data"); + fout.printtab(" "); + for(int i=0; i<=this.nItems; i++)fout.printtab(this.itemNames[i]); + fout.println(); + for(int i=0; i<=this.nItems; i++){ + fout.printtab(this.itemNames[i]); + for(int j=0; j<=this.nItems; j++)fout.printtab(Fmath.truncate(this.standardizedCorrelationCoefficients[i][j], this.trunc)); + fout.println(); + } + fout.println(); + + fout.print("Average inter-item correlation coefficient (excluding total) "); + fout.println(Fmath.truncate(this.standardizedMeanRhoWithoutTotals, this.trunc)); + fout.print("Standard deviation of the inter-item correlation coefficient (excluding total) "); + fout.println(Fmath.truncate(this.standardizedStandardDeviationRhoWithoutTotals, this.trunc)); + fout.print("Average inter-item correlation coefficient (including total) "); + fout.println(Fmath.truncate(this.standardizedMeanRhoWithTotals, this.trunc)); + fout.print("Standard deviation of the inter-item correlation coefficient (including total) "); + fout.println(Fmath.truncate(this.standardizedStandardDeviationRhoWithTotals, this.trunc)); + fout.println(); + + + // Item statistics + fout.println("ITEMS: MEANS, STANDARD DEVIATIONS, SKENESS AND KURTOSIS"); + fout.println("Raw data"); + fout.printtab("item "); + fout.printtab("mean"); + fout.printtab("standard"); + fout.printtab("moment"); + fout.printtab("median"); + fout.printtab("quartile"); + fout.printtab("kurtosis"); + fout.println("dichotomous"); + + fout.printtab(" "); + fout.printtab(" "); + fout.printtab("deviation"); + fout.printtab("skewness"); + fout.printtab("skewness"); + fout.printtab("skewness"); + fout.printtab("excess "); + fout.println("percentage"); + + for(int i=0; i<this.nItems; i++){ + fout.printtab(this.itemNames[i]); + fout.printtab(Fmath.truncate(this.rawItemMeans[i], this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemStandardDeviations[i], this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMomentSkewness[i], this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMedianSkewness[i], this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemQuartileSkewness[i], this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemKurtosisExcess[i], this.trunc)); + fout.println(Fmath.truncate(this.dichotomousPercentage[i], 1)); + } + fout.println(); + + fout.println("ITEMS: MINIMA, MAXIMA, MEDIANS, RANGES AND TOTALS"); + fout.println("raw data"); + fout.printtab("item "); + fout.printtab("minimum"); + fout.printtab("maximum"); + fout.printtab("median"); + fout.printtab("range"); + fout.printtab("total"); + fout.println("dichotomous"); + + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.println("percentage"); + + for(int i=0; i<this.nItems; i++){ + fout.printtab(this.itemNames[i]); + fout.printtab(Fmath.truncate(this.rawItemMinima[i], this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMaxima[i], this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMedians[i], this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemRanges[i], this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemTotals[i], this.trunc)); + fout.println(Fmath.truncate(this.dichotomousPercentage[i], 1)); + } + fout.println(); + + fout.printtab("item"); + fout.printtab("mean"); + fout.printtab("standard"); + fout.printtab("variance"); + fout.printtab("minimum"); + fout.printtab("maximum"); + fout.println("range"); + fout.printtab("statistic "); + fout.printtab(" "); + fout.printtab("deviation"); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.println(" "); + + fout.printtab("item means"); + fout.printtab(Fmath.truncate(this.rawItemMeansMean, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMeansSd, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMeansVar, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMeansMin, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMeansMax, this.trunc)); + fout.println(Fmath.truncate(this.rawItemMeansRange, this.trunc)); + + fout.printtab("item standard deviations"); + fout.printtab(Fmath.truncate(this.rawItemStandardDeviationsMean, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemStandardDeviationsSd, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemStandardDeviationsVar, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemStandardDeviationsMin, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemStandardDeviationsMax, this.trunc)); + fout.println(Fmath.truncate(this.rawItemStandardDeviationsRange, this.trunc)); + + fout.printtab("item variances"); + fout.printtab(Fmath.truncate(this.rawItemVariancesMean, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemVariancesSd, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemVariancesVar, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemVariancesMin, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemVariancesMax, this.trunc)); + fout.println(Fmath.truncate(this.rawItemVariancesRange, this.trunc)); + + fout.printtab("item mimima"); + fout.printtab(Fmath.truncate(this.rawItemMinimaMean, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMinimaSd, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMinimaVar, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMinimaMin, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMinimaMax, this.trunc)); + fout.println(Fmath.truncate(this.rawItemMinimaRange, this.trunc)); + + fout.printtab("item maxima"); + fout.printtab(Fmath.truncate(this.rawItemMaximaMean, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMaximaSd, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMaximaVar, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMaximaMin, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMaximaMax, this.trunc)); + fout.println(Fmath.truncate(this.rawItemMaximaRange, this.trunc)); + + fout.printtab("item medians"); + fout.printtab(Fmath.truncate(this.rawItemMediansMean, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMediansSd, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMediansVar, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMediansMin, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemMediansMax, this.trunc)); + fout.println(Fmath.truncate(this.rawItemMediansRange, this.trunc)); + + fout.printtab("item ranges"); + fout.printtab(Fmath.truncate(this.rawItemRangesMean, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemRangesSd, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemRangesVar, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemRangesMin, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemRangesMax, this.trunc)); + fout.println(Fmath.truncate(this.rawItemRangesRange, this.trunc)); + + fout.printtab("item totals"); + fout.printtab(Fmath.truncate(this.rawItemTotalsMean, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemTotalsSd, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemTotalsVar, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemTotalsMin, this.trunc)); + fout.printtab(Fmath.truncate(this.rawItemTotalsMax, this.trunc)); + fout.println(Fmath.truncate(this.rawItemTotalsRange, this.trunc)); + + fout.println(); + + fout.println("Standardized data"); + fout.println("ITEMS: MEANS, STANDARD DEVIATIONS, SKENESS AND KURTOSIS"); + fout.printtab("item "); + fout.printtab("mean"); + fout.printtab("standard"); + fout.printtab("moment"); + fout.printtab("median"); + fout.printtab("quartile"); + fout.println("kurtosis"); + + fout.printtab(" "); + fout.printtab(" "); + fout.printtab("deviation"); + fout.printtab("skewness"); + fout.printtab("skewness"); + fout.printtab("skewness"); + fout.println("excess "); + + for(int i=0; i<this.nItems; i++){ + fout.printtab(this.itemNames[i]); + fout.printtab(Fmath.truncate(this.standardizedItemMeans[i], this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemStandardDeviations[i], this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMomentSkewness[i], this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMedianSkewness[i], this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemQuartileSkewness[i], this.trunc)); + fout.println(Fmath.truncate(this.standardizedItemKurtosisExcess[i], this.trunc)); + } + fout.println(); + + fout.println("ITEMS: MINIMA, MAXIMA, MEDIANS, RANGES AND TOTALS"); + fout.println("Standardized data"); + fout.printtab("item "); + fout.printtab("minimum"); + fout.printtab("maximum"); + fout.printtab("median"); + fout.printtab("range"); + fout.println("total"); + + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.println(" "); + + for(int i=0; i<this.nItems; i++){ + fout.printtab(this.itemNames[i]); + fout.printtab(Fmath.truncate(this.standardizedItemMinima[i], this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMaxima[i], this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMedians[i], this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemRanges[i], this.trunc)); + fout.println(Fmath.truncate(this.standardizedItemTotals[i], this.trunc)); + } + fout.println(); + + + + fout.printtab("item"); + fout.printtab("mean"); + fout.printtab("standard"); + fout.printtab("variance"); + fout.printtab("minimum"); + fout.printtab("maximum"); + fout.println("range"); + + fout.printtab("statistic "); + fout.printtab(" "); + fout.printtab("deviation"); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.println(" "); + + fout.printtab("item means"); + fout.printtab(Fmath.truncate(this.standardizedItemMeansMean, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMeansSd, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMeansVar, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMeansMin, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMeansMax, this.trunc)); + fout.println(Fmath.truncate(this.standardizedItemMeansRange, this.trunc)); + + fout.printtab("item standard deviations"); + fout.printtab(Fmath.truncate(this.standardizedItemStandardDeviationsMean, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemStandardDeviationsSd, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemStandardDeviationsVar, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemStandardDeviationsMin, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemStandardDeviationsMax, this.trunc)); + fout.println(Fmath.truncate(this.standardizedItemStandardDeviationsRange, this.trunc)); + + fout.printtab("item variances"); + fout.printtab(Fmath.truncate(this.standardizedItemVariancesMean, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemVariancesSd, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemVariancesVar, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemVariancesMin, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemVariancesMax, this.trunc)); + fout.println(Fmath.truncate(this.standardizedItemVariancesRange, this.trunc)); + + fout.printtab("item mimima"); + fout.printtab(Fmath.truncate(this.standardizedItemMinimaMean, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMinimaSd, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMinimaVar, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMinimaMin, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMinimaMax, this.trunc)); + fout.println(Fmath.truncate(this.standardizedItemMinimaRange, this.trunc)); + + fout.printtab("item maxima"); + fout.printtab(Fmath.truncate(this.standardizedItemMaximaMean, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMaximaSd, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMaximaVar, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMaximaMin, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemMaximaMax, this.trunc)); + fout.println(Fmath.truncate(this.standardizedItemMaximaRange, this.trunc)); + + fout.print("item medians"); + fout.print(Fmath.truncate(this.rawItemMediansMean, this.trunc)); + fout.print(Fmath.truncate(this.rawItemMediansSd, this.trunc)); + fout.print(Fmath.truncate(this.rawItemMediansVar, this.trunc)); + fout.print(Fmath.truncate(this.rawItemMediansMin, this.trunc)); + fout.print(Fmath.truncate(this.rawItemMediansMax, this.trunc)); + fout.println(Fmath.truncate(this.rawItemMediansRange, this.trunc)); + + fout.printtab("item ranges"); + fout.printtab(Fmath.truncate(this.standardizedItemRangesMean, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemRangesSd, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemRangesVar, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemRangesMin, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemRangesMax, this.trunc)); + fout.println(Fmath.truncate(this.standardizedItemRangesRange, this.trunc)); + + fout.printtab("item totals"); + fout.printtab(Fmath.truncate(this.standardizedItemTotalsMean, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemTotalsSd, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemTotalsVar, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemTotalsMin, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedItemTotalsMax, this.trunc)); + fout.println(Fmath.truncate(this.standardizedItemTotalsRange, this.trunc)); + + fout.println(); + + fout.println("DELETION OF ITEMS"); + + fout.printtab(" "); + fout.printtab("Raw data "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.println("Standardized data"); + + fout.printtab("Deleted item"); + fout.printtab("Alpha "); + fout.printtab("Correlation "); + fout.printtab("Average "); + fout.printtab("Average "); + fout.printtab("Alpha "); + fout.printtab("Correlation "); + fout.printtab("Average "); + fout.println("Average "); + + + fout.printtab(" "); + fout.printtab(" "); + fout.printtab("coefficient"); + fout.printtab("inter-item "); + fout.printtab("inter-item "); + fout.printtab(" "); + fout.printtab("coefficient "); + fout.printtab("inter-item "); + fout.println("inter-item "); + + + fout.printtab(" "); + fout.printtab(" "); + fout.printtab("with total "); + fout.printtab("correlation"); + fout.printtab("correlation"); + fout.printtab(" "); + fout.printtab("with total "); + fout.printtab("correlation"); + fout.println("correlation"); + + + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab("coefficient"); + fout.printtab("coefficient"); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab("coefficient"); + fout.println("coefficient"); + + + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab("without totals"); + fout.printtab("with totals "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab("without totals"); + fout.println("with totals "); + + double[] newRawAlpha = new double[this.nItems]; + double[] newStandardizedAlpha = new double[this.nItems]; + double[] newRawRho = new double[this.nItems]; + double[] newStandardizedRho = new double[this.nItems]; + for(int i=0; i<this.nItems; i++){ + int index = i+1; + double[][] newScore1 = this.deleteItem(index); + Cronbach cr = new Cronbach(); + cr.enterScoresAsRowPerPerson(newScore1); + double rawAlphaD = cr.rawAlpha(); + newRawAlpha[i] = rawAlphaD; + double rawMeanRhoWithTotalsD = cr.rawAverageCorrelationCoefficientsWithTotals(); + double rawMeanRhoWithoutTotalsD = cr.rawAverageCorrelationCoefficients(); + double[] rawPersonTotalsD = cr.rawPersonTotals(); + double rawRhoAgainstTotalsD = Stat.corrCoeff(rawPersonTotalsD, this.scores0[i]); + newRawRho[i] = rawRhoAgainstTotalsD; + + double standardizedAlphaD = cr.standardizedAlpha(); + newStandardizedAlpha[i] = standardizedAlphaD; + double standardizedMeanRhoWithTotalsD = cr.standardizedAverageCorrelationCoefficientsWithTotals(); + double standardizedMeanRhoWithoutTotalsD = cr.standardizedAverageCorrelationCoefficients(); + double[] standardizedPersonTotalsD = cr.standardizedPersonTotals(); + double standardizedRhoAgainstTotalsD = Stat.corrCoeff(standardizedPersonTotalsD, this.scores0[i]); + newStandardizedRho[i] = standardizedRhoAgainstTotalsD; + + fout.printtab(this.itemNames[i]); + fout.printtab(Fmath.truncate(rawAlphaD, trunc)); + fout.printtab(Fmath.truncate(rawRhoAgainstTotalsD, trunc)); + fout.printtab(Fmath.truncate(rawMeanRhoWithoutTotalsD, trunc)); + fout.printtab(Fmath.truncate(rawMeanRhoWithTotalsD, trunc)); + + fout.printtab(Fmath.truncate(standardizedAlphaD, trunc)); + fout.printtab(Fmath.truncate(standardizedRhoAgainstTotalsD, trunc)); + fout.printtab(Fmath.truncate(standardizedMeanRhoWithoutTotalsD, trunc)); + fout.println(Fmath.truncate(standardizedMeanRhoWithTotalsD, trunc)); + } + fout.println(); + + fout.printtab("No item deleted"); + fout.printtab(Fmath.truncate(this.rawAlpha, trunc)); + fout.printtab(" "); + fout.printtab(Fmath.truncate(this.rawMeanRhoWithoutTotals, trunc)); + fout.printtab(Fmath.truncate(this.rawMeanRhoWithTotals, trunc)); + + fout.printtab(Fmath.truncate(this.standardizedAlpha, trunc)); + fout.printtab(" "); + fout.printtab(Fmath.truncate(this.standardizedMeanRhoWithoutTotals, trunc)); + fout.println(Fmath.truncate(this.standardizedMeanRhoWithTotals, trunc)); + fout.println(); + + // output a deleted item data file + this.deletedItemDataFile(newRawAlpha, newRawRho, newStandardizedAlpha, newStandardizedRho); + + + fout.println("INDIVIDUALS - raw data"); + fout.printtab("person "); + fout.printtab("mean"); + fout.printtab("standard"); + fout.printtab("minimum"); + fout.printtab("maximum"); + fout.printtab("range"); + fout.printtab("total"); + fout.println("scores:"); + + fout.printtab(" "); + fout.printtab(" "); + fout.printtab("deviation"); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + for(int i=0; i<this.nItems; i++)fout.printtab(this.itemNames[i]); + fout.println(); + + for(int i=0; i<this.nPersons; i++){ + fout.printtab((this.personIndices[i]+1)); + fout.printtab(Fmath.truncate(this.rawPersonMeans[i], this.trunc)); + fout.printtab(Fmath.truncate(this.rawPersonStandardDeviations[i], this.trunc)); + fout.printtab(Fmath.truncate(this.rawPersonMinima[i], this.trunc)); + fout.printtab(Fmath.truncate(this.rawPersonMaxima[i], this.trunc)); + fout.printtab(Fmath.truncate(this.rawPersonRanges[i], this.trunc)); + fout.printtab(Fmath.truncate(this.rawPersonTotals[i], this.trunc)); + for(int j=0; j<this.nItems; j++)fout.printtab(this.scores1[i][j]); + fout.println(); + } + fout.println(); + + fout.println("INDIVIDUALS - standardized data"); + fout.printtab("person "); + fout.printtab("mean"); + fout.printtab("standard"); + fout.printtab("minimum"); + fout.printtab("maximum"); + fout.printtab("range"); + fout.printtab("total"); + fout.println("scores:"); + + fout.printtab(" "); + fout.printtab(" "); + fout.printtab("deviation"); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + for(int i=0; i<this.nItems; i++)fout.printtab(this.itemNames[i]); + fout.println(); + + + for(int i=0; i<this.nPersons; i++){ + fout.printtab((this.personIndices[i]+1)); + fout.printtab(Fmath.truncate(this.standardizedPersonMeans[i], this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedPersonStandardDeviations[i], this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedPersonMinima[i], this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedPersonMaxima[i], this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedPersonRanges[i], this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedPersonTotals[i], this.trunc)); + for(int j=0; j<this.nItems; j++)fout.printtab(Fmath.truncate(this.standardizedScores1[i][j], trunc)); + fout.println(); + } + fout.println(); + + fout.println("ALL SCORES - raw data"); + + fout.printtab("mean"); + fout.printtab("standard"); + fout.printtab("minimum"); + fout.printtab("maximum"); + fout.printtab("range"); + fout.println("overall"); + fout.printtab(" "); + fout.printtab("deviation"); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.println("total"); + + fout.printtab(Fmath.truncate(this.rawAllResponsesMean, this.trunc)); + fout.printtab(Fmath.truncate(this.rawAllResponsesStandardDeviation, this.trunc)); + fout.printtab(Fmath.truncate(this.rawAllResponsesMinimum, this.trunc)); + fout.printtab(Fmath.truncate(this.rawAllResponsesMaximum, this.trunc)); + fout.printtab(Fmath.truncate(this.rawAllResponsesRange, this.trunc)); + fout.println(Fmath.truncate(this.rawAllResponsesTotal, this.trunc)); + fout.println(); + + fout.println("ALL SCORES - standardized data"); + + fout.printtab("mean"); + fout.printtab("standard"); + fout.printtab("minimum"); + fout.printtab("maximum"); + fout.printtab("range"); + fout.println("overall"); + fout.printtab(" "); + fout.printtab("deviation"); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.println("total"); + + fout.printtab(Fmath.truncate(this.standardizedAllResponsesMean, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedAllResponsesStandardDeviation, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedAllResponsesMinimum, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedAllResponsesMaximum, this.trunc)); + fout.printtab(Fmath.truncate(this.standardizedAllResponsesRange, this.trunc)); + fout.println(Fmath.truncate(this.standardizedAllResponsesTotal, this.trunc)); + fout.println(); + + // close output file + fout.close(); + } + + + private void analysisText(){ + + FileOutput fout = null; + if(this.fileNumberingSet){ + fout = new FileOutput(this.outputFilename, 'n'); + } + else{ + fout = new FileOutput(this.outputFilename); + } + + // calculate alphas if not already calculated + if(!rawAlphaCalculated)this.rawAlpha(); + if(!standardizedAlphaCalculated)this.standardizedAlpha(); + + // output title information + fout.println("CRONBACH'S ALPHA RELIABILITY ESTIMATOR"); + fout.println("Program: Cronbach - Analysis Output"); + for(int i=0; i<this.titleLines; i++)fout.println(title[i]); + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + fout.println("Program executed at " + tim + " on " + day); + fout.println(); + + // output reliability estimators + int field = 36; // field width + fout.println("RELIABILITY ESTIMATORS"); + fout.println("Cronbach's coefficient alpha"); + fout.print("Raw data ", field); + fout.println(Fmath.truncate(this.rawAlpha, this.trunc)); + fout.print("Standardized data ", field); + fout.println(Fmath.truncate(this.standardizedAlpha, this.trunc)); + fout.println(); + + fout.println("Average of the inter-item correlation coefficients, excluding item totals"); + fout.print("Raw data ", field); + fout.println(Fmath.truncate(this.rawMeanRhoWithoutTotals, this.trunc)); + fout.print("Standardized data ", field); + fout.println(Fmath.truncate(this.standardizedMeanRhoWithoutTotals, this.trunc)); + fout.println(); + + fout.println("Average of the inter-item correlation coefficients, including item totals"); + fout.print("Raw data ", field); + fout.println(Fmath.truncate(this.rawMeanRhoWithTotals, this.trunc)); + fout.print("Standardized data ", field); + fout.println(Fmath.truncate(this.standardizedMeanRhoWithTotals, this.trunc)); + fout.println(); + + // output any deletions or replacements + fout.println("'NO RESPONSE' DELETIONS AND REPLACEMENTS"); + // deleted persons + field = 34; + int fieldInt = 6; + boolean deletionFlag = false; + if(this.nDeletedPersons!=0){ + deletionFlag = true; + fout.print("Number of persons deleted ", field); + fout.println(this.nDeletedPersons); + fout.print("Indices of deleted persons: ", field); + for(int i=0; i<this.nDeletedPersons; i++)fout.print((this.deletedPersonsIndices[i]+1), fieldInt); + fout.println(); + } + else{ + fout.println("No persons were deleted "); + } + + // deleted items + if(this.nDeletedItems!=0){ + deletionFlag = true; + fout.print("Number of items deleted ", field); + fout.println(this.nDeletedItems); + fout.print("Names of deleted items: ", field); + for(int i=0; i<this.nDeletedItems; i++)fout.print(this.originalItemNames[this.deletedItemsIndices[i]], fieldInt); + fout.println(); + } + else{ + fout.println("No items were deleted "); + } + + // replacements + if(this.nReplacements!=0){ + fout.printtab("Number of 'no responses' replaced "); + fout.println(this.nReplacements); + fout.print("Item name and person index of replacements: ", 50); + for(int i=0; i<this.nReplacements; i++)fout.print(this.replacementIndices[i], fieldInt); + fout.print("Replacement option: ", field); + fout.println(this.replacementOptionNames[this.replacementOption-1]); + fout.println(); + } + else{ + if(deletionFlag){ + fout.println("No 'no response' replacements, other than any above deletions, were made "); + } + else{ + fout.println("No 'no response' replacements were made "); + } + } + fout.println(); + fout.print("Number of items used", 35); + fout.println(this.nItems); + fout.print("Number of persons used", 35); + fout.println(this.nPersons); + fout.println(); + + // Correlation coefficients + int len = trunc+8; + int fieldItemName = 0; + for(int i=0; i<=this.nItems; i++)if(this.itemNames[i].length()>fieldItemName)fieldItemName = this.itemNames[i].length(); + int fieldItemNumber = fieldItemName; + if(len>fieldItemNumber)fieldItemNumber = len; + fieldItemName++; + fieldItemNumber++; + + fout.println("CORRELATION COEFFICIENTS"); + fout.println("Correlation coefficients between items - raw data"); + fout.print(" ", fieldItemName); + + for(int i=0; i<=this.nItems; i++)fout.print(this.itemNames[i], fieldItemNumber); + fout.println(); + for(int i=0; i<=this.nItems; i++){ + fout.print(this.itemNames[i], fieldItemName); + for(int j=0; j<=this.nItems; j++)fout.print(Fmath.truncate(this.rawCorrelationCoefficients[i][j], this.trunc), fieldItemNumber); + fout.println(); + } + fout.println(); + + fout.print("Average inter-item correlation coefficient (excluding total) ", 80); + fout.println(Fmath.truncate(this.rawMeanRhoWithoutTotals, this.trunc)); + fout.print("Standard deviation of the inter-item correlation coefficient (excluding total) ", 80); + fout.println(Fmath.truncate(this.rawStandardDeviationRhoWithoutTotals, this.trunc)); + fout.print("Average inter-item correlation coefficient (including total) ", 80); + fout.println(Fmath.truncate(this.rawMeanRhoWithTotals, this.trunc)); + fout.print("Standard deviation of the inter-item correlation coefficient (including total) ", 80); + fout.println(Fmath.truncate(this.rawStandardDeviationRhoWithTotals, this.trunc)); + + fout.println(); + + + fout.println("Correlation coefficients between items - standardized data"); + fout.print(" ", fieldItemName); + for(int i=0; i<=this.nItems; i++)fout.print(this.itemNames[i], fieldItemNumber); + fout.println(); + for(int i=0; i<=this.nItems; i++){ + fout.print(this.itemNames[i], fieldItemName); + for(int j=0; j<=this.nItems; j++)fout.print(Fmath.truncate(this.standardizedCorrelationCoefficients[i][j], this.trunc), fieldItemNumber); + fout.println(); + } + fout.println(); + + fout.print("Average inter-item correlation coefficient (excluding total) ", 80); + fout.println(Fmath.truncate(this.standardizedMeanRhoWithoutTotals, this.trunc)); + fout.print("Standard deviation of the inter-item correlation coefficient (excluding total) ", 80); + fout.println(Fmath.truncate(this.standardizedStandardDeviationRhoWithoutTotals, this.trunc)); + fout.print("Average inter-item correlation coefficient (including total) ", 80); + fout.println(Fmath.truncate(this.standardizedMeanRhoWithTotals, this.trunc)); + fout.print("Standard deviation of the inter-item correlation coefficient (including total) ", 80); + fout.println(Fmath.truncate(this.standardizedStandardDeviationRhoWithTotals, this.trunc)); + fout.println(); + + // item statistics + if(fieldItemNumber<12)fieldItemNumber = 12; + + fout.println("ITEMS: MEANS, STANDARD DEVIATIONS, SKENESS AND KURTOSIS"); + fout.println("Raw data"); + fout.print("item ", fieldItemName); + fout.print("mean", fieldItemNumber); + fout.print("standard", fieldItemNumber); + fout.print("moment", fieldItemNumber); + fout.print("median", fieldItemNumber); + fout.print("quartile", fieldItemNumber); + fout.print("kurtosis", fieldItemNumber); + fout.println("dichotomous"); + + fout.print(" ", fieldItemName); + fout.print(" ", fieldItemNumber); + fout.print("deviation", fieldItemNumber); + fout.print("skewness", fieldItemNumber); + fout.print("skewness", fieldItemNumber); + fout.print("skewness", fieldItemNumber); + fout.print("excess ", fieldItemNumber); + fout.println("percentage"); + + for(int i=0; i<this.nItems; i++){ + fout.print(this.itemNames[i], fieldItemName); + fout.print(Fmath.truncate(this.rawItemMeans[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemStandardDeviations[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMomentSkewness[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMedianSkewness[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemQuartileSkewness[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemKurtosisExcess[i], this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.dichotomousPercentage[i], 1)); + } + fout.println(); + + fout.println("ITEMS: MINIMA, MAXIMA, MEDIANS, RANGES AND TOTALS"); + fout.println("Raw data"); + fout.print("item ", fieldItemName); + fout.print("minimum", fieldItemNumber); + fout.print("maximum", fieldItemNumber); + fout.print("median", fieldItemNumber); + fout.print("range", fieldItemNumber); + fout.print("total", fieldItemNumber); + fout.println("dichotomous"); + + fout.print(" ", fieldItemName); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.println("percentage"); + + for(int i=0; i<this.nItems; i++){ + fout.print(this.itemNames[i], fieldItemName); + fout.print(Fmath.truncate(this.rawItemMinima[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMaxima[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMedians[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemRanges[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemTotals[i], this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.dichotomousPercentage[i], 1)); + } + fout.println(); + + int fieldItemSName = 25; + fout.print("item", fieldItemSName); + fout.print("mean", fieldItemNumber); + fout.print("standard", fieldItemNumber); + fout.print("variance", fieldItemNumber); + fout.print("minimum", fieldItemNumber); + fout.print("maximum", fieldItemNumber); + fout.println("range"); + fout.print("statistic ", fieldItemSName); + fout.print(" ", fieldItemNumber); + fout.print("deviation", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.println(" "); + + fout.print("item means", fieldItemSName); + fout.print(Fmath.truncate(this.rawItemMeansMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMeansSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMeansVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMeansMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMeansMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.rawItemMeansRange, this.trunc)); + + fout.print("item standard deviations", fieldItemSName); + fout.print(Fmath.truncate(this.rawItemStandardDeviationsMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemStandardDeviationsSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemStandardDeviationsVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemStandardDeviationsMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemStandardDeviationsMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.rawItemStandardDeviationsRange, this.trunc)); + + fout.print("item variances", fieldItemSName); + fout.print(Fmath.truncate(this.rawItemVariancesMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemVariancesSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemVariancesVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemVariancesMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemVariancesMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.rawItemVariancesRange, this.trunc)); + + fout.print("item mimima", fieldItemSName); + fout.print(Fmath.truncate(this.rawItemMinimaMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMinimaSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMinimaVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMinimaMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMinimaMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.rawItemMinimaRange, this.trunc)); + + fout.print("item maxima", fieldItemSName); + fout.print(Fmath.truncate(this.rawItemMaximaMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMaximaSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMaximaVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMaximaMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMaximaMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.rawItemMaximaRange, this.trunc)); + + fout.print("item medians", fieldItemSName); + fout.print(Fmath.truncate(this.rawItemMediansMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMediansSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMediansVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMediansMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemMediansMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.rawItemMediansRange, this.trunc)); + + fout.print("item ranges", fieldItemSName); + fout.print(Fmath.truncate(this.rawItemRangesMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemRangesSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemRangesVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemRangesMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemRangesMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.rawItemRangesRange, this.trunc)); + + fout.print("item totals", fieldItemSName); + fout.print(Fmath.truncate(this.rawItemTotalsMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemTotalsSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemTotalsVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemTotalsMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawItemTotalsMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.rawItemTotalsRange, this.trunc)); + + fout.println(); + + fout.println("standardized data"); + fout.print("item ", fieldItemName); + fout.print("mean", fieldItemNumber); + fout.print("standard", fieldItemNumber); + fout.print("moment", fieldItemNumber); + fout.print("median", fieldItemNumber); + fout.print("quartile", fieldItemNumber); + fout.println("kurtosis"); + + fout.print(" ", fieldItemName); + fout.print(" ", fieldItemNumber); + fout.print("deviation", fieldItemNumber); + fout.print("skewness", fieldItemNumber); + fout.print("skewness", fieldItemNumber); + fout.print("skewness", fieldItemNumber); + fout.println("excess "); + + for(int i=0; i<this.nItems; i++){ + fout.print(this.itemNames[i], fieldItemName); + fout.print(Fmath.truncate(this.standardizedItemMeans[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemStandardDeviations[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMomentSkewness[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMedianSkewness[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemQuartileSkewness[i], this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.standardizedItemKurtosisExcess[i], this.trunc)); + } + fout.println(); + + fout.print("item ", fieldItemName); + fout.print("minimum", fieldItemNumber); + fout.print("maximum", fieldItemNumber); + fout.print("median", fieldItemNumber); + fout.print("range", fieldItemNumber); + fout.println("total"); + + fout.print(" ", fieldItemName); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.println(" "); + + for(int i=0; i<this.nItems; i++){ + fout.print(this.itemNames[i], fieldItemName); + fout.print(Fmath.truncate(this.standardizedItemMinima[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMaxima[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMedians[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemRanges[i], this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.standardizedItemTotals[i], this.trunc)); + } + fout.println(); + + + fout.print("item", fieldItemSName); + fout.print("mean", fieldItemNumber); + fout.print("standard", fieldItemNumber); + fout.print("variance", fieldItemNumber); + fout.print("minimum", fieldItemNumber); + fout.print("maximum", fieldItemNumber); + fout.println("range"); + fout.print("statistic ", fieldItemSName); + fout.print(" ", fieldItemNumber); + fout.print("deviation", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.println(" "); + + fout.print("item means", fieldItemSName); + fout.print(Fmath.truncate(this.standardizedItemMeansMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMeansSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMeansVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMeansMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMeansMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.standardizedItemMeansRange, this.trunc)); + + fout.print("item standard deviations", fieldItemSName); + fout.print(Fmath.truncate(this.standardizedItemStandardDeviationsMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemStandardDeviationsSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemStandardDeviationsVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemStandardDeviationsMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemStandardDeviationsMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.standardizedItemStandardDeviationsRange, this.trunc)); + + fout.print("item variances", fieldItemSName); + fout.print(Fmath.truncate(this.standardizedItemVariancesMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemVariancesSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemVariancesVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemVariancesMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemVariancesMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.standardizedItemVariancesRange, this.trunc)); + + fout.print("item mimima", fieldItemSName); + fout.print(Fmath.truncate(this.standardizedItemMinimaMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMinimaSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMinimaVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMinimaMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMinimaMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.standardizedItemMinimaRange, this.trunc)); + + fout.print("item maxima", fieldItemSName); + fout.print(Fmath.truncate(this.standardizedItemMaximaMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMaximaSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMaximaVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMaximaMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMaximaMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.standardizedItemMaximaRange, this.trunc)); + + fout.print("item medians", fieldItemSName); + fout.print(Fmath.truncate(this.standardizedItemMediansMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMediansSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMediansVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMediansMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemMediansMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.standardizedItemMediansRange, this.trunc)); + + fout.print("item ranges", fieldItemSName); + fout.print(Fmath.truncate(this.standardizedItemRangesMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemRangesSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemRangesVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemRangesMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemRangesMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.standardizedItemRangesRange, this.trunc)); + + fout.print("item totals", fieldItemSName); + fout.print(Fmath.truncate(this.standardizedItemTotalsMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemTotalsSd, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemTotalsVar, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemTotalsMin, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedItemTotalsMax, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.standardizedItemTotalsRange, this.trunc)); + + fout.println(); + + + fout.println("DELETION OF ITEMS"); + int fieldDitem = 16; + if(fieldItemName>fieldDitem)fieldDitem=fieldItemName; + + fout.print(" ", fieldDitem); + fout.print("Raw data", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.println("Standardized data"); + + fout.print("Deleted item", fieldDitem); + fout.print("Alpha", fieldItemNumber); + fout.print("Correlation", fieldItemNumber); + fout.print("Average", fieldItemNumber); + fout.print("Average", fieldItemNumber); + + fout.print("Alpha", fieldItemNumber); + fout.print("Correlation", fieldItemNumber); + fout.print("Average", fieldItemNumber); + fout.println("Average"); + + + fout.print(" ", fieldDitem); + fout.print(" ", fieldItemNumber); + fout.print("coefficient", fieldItemNumber); + fout.print("inter-item", fieldItemNumber); + fout.print("inter-item", fieldItemNumber); + + fout.print(" ", fieldItemNumber); + fout.print("coefficient", fieldItemNumber); + fout.print("inter-item", fieldItemNumber); + fout.println("inter-item"); + + + fout.print(" ", fieldDitem); + fout.print(" ", fieldItemNumber); + fout.print("with total", fieldItemNumber); + fout.print("correlation", fieldItemNumber); + fout.print("correlation", fieldItemNumber); + + fout.print(" ", fieldItemNumber); + fout.print("with total", fieldItemNumber); + fout.print("correlation", fieldItemNumber); + fout.println("correlation"); + + + fout.print(" ", fieldDitem); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print("coefficient", fieldItemNumber); + fout.print("coefficient", fieldItemNumber); + + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print("coefficient", fieldItemNumber); + fout.println("coefficient"); + + + fout.print(" ", fieldDitem); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print("without totals", fieldItemNumber); + fout.print("with totals", fieldItemNumber); + + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print("without totals", fieldItemNumber); + fout.println("with totals"); + + double[] newRawAlpha = new double[this.nItems]; + double[] newStandardizedAlpha = new double[this.nItems]; + double[] newRawRho = new double[this.nItems]; + double[] newStandardizedRho = new double[this.nItems]; + for(int i=0; i<this.nItems; i++){ + int index = i+1; + double[][] newScore1 = this.deleteItem(index); + Cronbach cr = new Cronbach(); + cr.enterScoresAsRowPerPerson(newScore1); + double rawAlphaD = cr.rawAlpha(); + newRawAlpha[i] = rawAlphaD; + double rawMeanRhoWithTotalsD = cr.rawAverageCorrelationCoefficientsWithTotals(); + double[] rawPersonTotalsD = cr.rawPersonTotals(); + double rawRhoAgainstTotalsD = Stat.corrCoeff(rawPersonTotalsD, this.scores0[i]); + double rawMeanRhoWithoutTotalsD = cr.rawAverageCorrelationCoefficients(); + newRawRho[i] = rawRhoAgainstTotalsD; + + double standardizedAlphaD = cr.standardizedAlpha(); + newStandardizedAlpha[i] = standardizedAlphaD; + double standardizedMeanRhoWithTotalsD = cr.standardizedAverageCorrelationCoefficients(); + double[] standardizedPersonTotalsD = cr.standardizedPersonTotals(); + double standardizedRhoAgainstTotalsD = Stat.corrCoeff(standardizedPersonTotalsD, this.scores0[i]); + double standardizedMeanRhoWithoutTotalsD = cr.standardizedAverageCorrelationCoefficients(); + newStandardizedRho[i] = standardizedRhoAgainstTotalsD; + + fout.print(this.itemNames[i], fieldDitem); + fout.print(Fmath.truncate(rawAlphaD, trunc), fieldItemNumber); + fout.print(Fmath.truncate(rawRhoAgainstTotalsD, trunc), fieldItemNumber); + fout.print(Fmath.truncate(rawMeanRhoWithoutTotalsD, trunc), fieldItemNumber); + fout.print(Fmath.truncate(rawMeanRhoWithTotalsD, trunc), fieldItemNumber); + + fout.print(Fmath.truncate(standardizedAlphaD, trunc), fieldItemNumber); + fout.print(Fmath.truncate(standardizedRhoAgainstTotalsD, trunc), fieldItemNumber); + fout.print(Fmath.truncate(standardizedMeanRhoWithoutTotalsD, trunc), fieldItemNumber); + fout.print(Fmath.truncate(standardizedMeanRhoWithTotalsD, trunc), fieldItemNumber); + fout.println(); + } + fout.println(); + + fout.print("No item deleted", fieldDitem); + fout.print(Fmath.truncate(this.rawAlpha, trunc), fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(Fmath.truncate(this.rawMeanRhoWithoutTotals, trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawMeanRhoWithTotals, trunc), fieldItemNumber); + + fout.print(Fmath.truncate(this.standardizedAlpha, trunc), fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedMeanRhoWithoutTotals, trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.standardizedMeanRhoWithTotals, trunc)); + fout.println(); + + // output a deleted item data file + this.deletedItemDataFile(newRawAlpha, newRawRho, newStandardizedAlpha, newStandardizedRho); + + int fieldInd = 12; + fout.println("INDIVIDUALS - raw data"); + fout.print("person", fieldInd); + fout.print("mean", fieldItemNumber); + fout.print("standard", fieldItemNumber); + fout.print("minimum", fieldItemNumber); + fout.print("maximum", fieldItemNumber); + fout.print("range", fieldItemNumber); + fout.println("total"); + + fout.print(" ", fieldInd); + fout.print(" ", fieldItemNumber); + fout.print("deviation", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.println(" "); + + int fieldScore = 0; + for(int i=0; i<this.nItems; i++){ + for(int j=0; j<this.nPersons; j++){ + int sl = Double.toString(scores0[i][j]).length(); + if(sl>fieldScore)fieldScore = sl; + } + } + fieldScore++; + if(fieldScore<fieldItemName)fieldScore = fieldItemName; + for(int i=0; i<this.nPersons; i++){ + fout.print((this.personIndices[i]+1), fieldInd); + fout.print(Fmath.truncate(this.rawPersonMeans[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawPersonStandardDeviations[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawPersonMinima[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawPersonMaxima[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawPersonRanges[i], this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.rawPersonTotals[i], this.trunc)); + } + fout.println(); + + fout.println("scores:"); + fout.print("person ", fieldInd); + for(int i=0; i<this.nItems; i++)fout.print(this.itemNames[i], fieldScore); + fout.println(); + + for(int i=0; i<this.nPersons; i++){ + fout.print((this.personIndices[i]+1), fieldInd); + for(int j=0; j<this.nItems; j++)fout.print(this.scores1[i][j], fieldScore); + fout.println(); + } + fout.println(); + + fout.println("INDIVIDUALS - standardized data"); + fout.print("person ", fieldInd); + fout.print("mean", fieldItemNumber); + fout.print("standard", fieldItemNumber); + fout.print("minimum", fieldItemNumber); + fout.print("maximum", fieldItemNumber); + fout.print("range", fieldItemNumber); + fout.println("total"); + + + fout.print(" ", fieldInd); + fout.print(" ", fieldItemNumber); + fout.print("deviation", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.println(" "); + + for(int i=0; i<this.nPersons; i++){ + fout.print((this.personIndices[i]+1), fieldInd); + fout.print(Fmath.truncate(this.standardizedPersonMeans[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedPersonStandardDeviations[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedPersonMinima[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedPersonMaxima[i], this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedPersonRanges[i], this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.standardizedPersonTotals[i], this.trunc)); + } + fout.println(); + + fout.println("scores:"); + fout.print("person ", fieldInd); + for(int i=0; i<this.nItems; i++)fout.print(this.itemNames[i], fieldItemNumber); + fout.println(); + + for(int i=0; i<this.nPersons; i++){ + fout.print((this.personIndices[i]+1), fieldInd); + for(int j=0; j<this.nItems; j++)fout.print(Fmath.truncate(this.standardizedScores1[i][j], trunc), fieldItemNumber); + fout.println(); + } + fout.println(); + + fout.println("ALL SCORES - raw data"); + fout.print("mean", fieldItemNumber); + fout.print("standard", fieldItemNumber); + fout.print("minimum", fieldItemNumber); + fout.print("maximum", fieldItemNumber); + fout.print("range", fieldItemNumber); + fout.println("overall"); + + fout.print(" ", fieldItemNumber); + fout.print("deviation", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.println("total"); + + fout.print(Fmath.truncate(this.rawAllResponsesMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawAllResponsesStandardDeviation, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawAllResponsesMinimum, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawAllResponsesMaximum, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.rawAllResponsesRange, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.rawAllResponsesTotal, this.trunc)); + fout.println(); + + fout.println("ALL SCORES - standardized data"); + fout.print("mean", fieldItemNumber); + fout.print("standard", fieldItemNumber); + fout.print("minimum", fieldItemNumber); + fout.print("maximum", fieldItemNumber); + fout.print("range", fieldItemNumber); + fout.println("overall"); + + fout.print(" ", fieldItemNumber); + fout.print("deviation", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.print(" ", fieldItemNumber); + fout.println("total"); + + fout.print(Fmath.truncate(this.standardizedAllResponsesMean, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedAllResponsesStandardDeviation, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedAllResponsesMinimum, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedAllResponsesMaximum, this.trunc), fieldItemNumber); + fout.print(Fmath.truncate(this.standardizedAllResponsesRange, this.trunc), fieldItemNumber); + fout.println(Fmath.truncate(this.standardizedAllResponsesTotal, this.trunc)); + fout.println(); + + + // close output file + fout.close(); + } + + // Creation of a data file facilitating a full analysis of the data minus the least consitent item + private void deletedItemDataFile(double[] newRawAlpha, double[] newRawRho, double[] newStandardizedAlpha, double[] newStandardizedRho){ + + // Find maximum alpha and minimum correlation with totals + ArrayMaths am = new ArrayMaths(newRawAlpha); + int index1 = am.maximumIndex(); + am = new ArrayMaths(newStandardizedAlpha); + int index2 = am.maximumIndex(); + am = new ArrayMaths(newRawRho); + int index3 = am.minimumIndex(); + am = new ArrayMaths(newStandardizedRho); + int index4 = am.minimumIndex(); + + + // majority voting on least consistent item + this.deletedItemIndex = index3; + if(index1==index2 && index1==index3 && index1==index4){ + this.deletedItemIndex = index1; + } + else{ + if(index1==index2 && (index1==index3 || index1==index4)){ + this.deletedItemIndex = index1; + } + else{ + if(index4==index3 && (index4==index1 || index4==index2)){ + this.deletedItemIndex = index4; + } + else{ + if(index1==index2 && index3==index4){ + this.deletedItemIndex = index3; + } + else{ + if(index1==index3 && index2==index4){ + this.deletedItemIndex = index1; + } + else{ + if(index1!=index2 && index2!=index3 && index3!=index4){ + this.deletedItemIndex = index3; + } + } + } + } + } + } + + String deletedFilename = null; + if(this.inputFilename!=null){ + deletedFilename = this.inputFilename; + int pos = deletedFilename.indexOf("."); + if(pos!=-1)deletedFilename = deletedFilename.substring(0,pos); + deletedFilename = deletedFilename + "_" + this.itemNames[this.deletedItemIndex]+"_deleted"; + deletedFilename = deletedFilename + ".txt"; + } + else{ + deletedFilename = "DeletedItemFile.txt"; + } + + FileOutput dfout = new FileOutput(deletedFilename); + String newTitle = title[0] + " - Item " + this.itemNames[this.deletedItemIndex] + " deleted"; + dfout.println(newTitle); + dfout.println((this.nItems-1)); + dfout.println(this.nPersons); + for(int i=0; i<this.nItems; i++){ + if(i!=this.deletedItemIndex)dfout.printtab(this.itemNames[i]); + } + dfout.println(); + if(this.originalDataType==0){ + for(int i=0; i<this.nItems; i++){ + if(i!=this.deletedItemIndex){ + for(int j=0; j<this.nPersons; j++){ + dfout.printtab(this.scores0[i][j]); + } + dfout.println(); + } + } + } + else{ + for(int j=0; j<this.nPersons; j++){ + for(int i=0; i<this.nItems; i++){ + if(i!=this.deletedItemIndex){ + dfout.printtab(this.scores1[j][i]); + } + } + dfout.println(); + } + } + dfout.close(); + } + + +} \ No newline at end of file diff --git a/src/main/java/flanagan/analysis/ErrorProp.java b/src/main/java/flanagan/analysis/ErrorProp.java new file mode 100755 index 0000000000000000000000000000000000000000..86ab36f309756ce9c88f300724f873ca92c97d16 --- /dev/null +++ b/src/main/java/flanagan/analysis/ErrorProp.java @@ -0,0 +1,1035 @@ +/* +* Class ErrorProp +* +* Defines an object consisting of a variable and its associated standard +* deviation and the class includes the methods for propagating the error +* in standard arithmetic operations for both correlated and uncorrelated +* errors. +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: October 2002 +* UPDATE: 26 April 2004, 19 January 2005 +* +* See ComplexErrorProp for the propogation of errors in complex arithmetic +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ErrorProp.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Redistributions of this source code, or parts of, must retain the above +* copyright notice, this list of conditions and the following disclaimer. +* +* Redistribution in binary form of all or parts of this class, must reproduce +* the above copyright, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the distribution. +* +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all +* copies and associated documentation or publications. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.analysis; + +import flanagan.math.Fmath; + +public class ErrorProp{ + + // DATA VARIABLES + private double value = 0.0D; // number value + private double error = 0.0D; // its standard deviation or an estimate of its standard deviation + + + // CONSTRUCTORS + // default constructor + public ErrorProp(){ + value = 0.0; + error = 0.0; + } + + // constructor with value and error initialised + public ErrorProp(double value, double error){ + this.value = value; + this.error = error; + } + + // constructor with value initialised + public ErrorProp(double value){ + this.value = value; + this.error = 0.0; + } + + // PUBLIC METHODS + + // SET VALUES + // Set the value of value + public void setValue(double value){ + this.value = value; + } + + // Set the value of error + public void setError(double error){ + this.error = error; + } + + // Set the values of value and error + public void reset(double value, double error){ + this.value = value; + this.error = error; + } + + // GET VALUES + // Get the value of value + public double getValue(){ + return value; + } + + // Get the value of error + public double getError(){ + return error; + } + + //PRINT AN ERROR NUMBER + // Print to terminal window with text (message) and a line return + public void println(String message){ + System.out.println(message + " " + this.toString()); + } + + // Print to terminal window without text (message) but with a line return + public void println(){ + System.out.println(" " + this.toString()); + } + + // Print to terminal window with text (message) but without line return + public void print(String message){ + System.out.print(message + " " + this.toString()); + } + + // Print to terminal window without text (message) and without line return + public void print(){ + System.out.print(" " + this.toString()); + } + + // TRUNCATION + // Rounds the mantissae of both the value and error parts of Errorprop to prec places + public static ErrorProp truncate(ErrorProp x, int prec){ + if(prec<0)return x; + + double xV = x.getValue(); + double xS = x.getError(); + ErrorProp y = new ErrorProp(); + + xV = Fmath.truncate(xV, prec); + xS = Fmath.truncate(xS, prec); + + y.reset(xV, xS); + + return y; + } + + // instance method + public ErrorProp truncate(int prec){ + if(prec<0)return this; + + double xV = this.getValue(); + double xS = this.getError(); + ErrorProp y = new ErrorProp(); + + xV = Fmath.truncate(xV, prec); + xS = Fmath.truncate(xS, prec); + + y.reset(xV, xS); + + return y; + } + + // CONVERSIONS + // Format an ErrorProp number as a string + // Overides java.lang.String.toString() + public String toString(){ + return this.value+", error = "+this.error; + } + + // Format an ErrorProp number as a string + // See static method above for comments + public static String toString(ErrorProp aa){ + return aa.value+", error = "+aa.error; + } + + // Return a HASH CODE for the ErrorProp number + // Overides java.lang.Object.hashCode() + public int hashCode(){ + long lvalue = Double.doubleToLongBits(this.value); + long lerror = Double.doubleToLongBits(this.error); + int hvalue = (int)(lvalue^(lvalue>>>32)); + int herror = (int)(lerror^(lerror>>>32)); + return 7*(hvalue/10)+3*(herror/10); + } + + + // ARRAYS + + // Create a one dimensional array of ErrorProp objects of length n + // all values = 0 and all error's = 0 + public static ErrorProp[] oneDarray(int n){ + ErrorProp[] a =new ErrorProp[n]; + for(int i=0; i<n; i++){ + a[i]=ErrorProp.zero(); + } + return a; + } + + // Create a one dimensional array of ErrorProp objects of length n + // all values = a and all error's = b + public static ErrorProp[] oneDarray(int n, double a, double b){ + ErrorProp[] c =new ErrorProp[n]; + for(int i=0; i<n; i++){ + c[i]=ErrorProp.zero(); + c[i].reset(a, b); + } + return c; + } + + // Create a one dimensional array of ErrorProp objects of length n + // all = the ErrorProp number named constant + public static ErrorProp[] oneDarray(int n, ErrorProp constant){ + ErrorProp[] c =new ErrorProp[n]; + for(int i=0; i<n; i++){ + c[i]=ErrorProp.copy(constant); + } + return c; + } + + // Create a two dimensional array of ErrorProp objects of dimensions n and m + // all values = zero and all error's = zero + public static ErrorProp[][] twoDarray(int n, int m){ + ErrorProp[][] a =new ErrorProp[n][m]; + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + a[i][j]=ErrorProp.zero(); + } + } + return a; + } + + // Create a two dimensional array of ErrorProp objects of dimensions n and m + // all values = a and all error's = b + public static ErrorProp[][] twoDarray(int n, int m, double a, double b){ + ErrorProp[][] c =new ErrorProp[n][m]; + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + c[i][j]=ErrorProp.zero(); + c[i][j].reset(a, b); + } + } + return c; + } + + // Create a two dimensional array of ErrorProp objects of dimensions n and m + // all = the ErrorProp number named constant + public static ErrorProp[][] twoDarray(int n, int m, ErrorProp constant){ + ErrorProp[][] c =new ErrorProp[n][m]; + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + c[i][j]=ErrorProp.copy(constant); + } + } + return c; + } + + // COPY + // Copy a single ErrorProp number [static method] + public static ErrorProp copy(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = a.value; + b.error = a.error; + return b; + } + + // Copy a single ErrorProp number [instance method] + public ErrorProp copy(){ + ErrorProp b = new ErrorProp(); + b.value = this.value; + b.error = this.error; + return b; + } + + // Clone a single ErrorProp number + public Object clone(){ + ErrorProp b = new ErrorProp(); + b.value = this.value; + b.error = this.error; + return (Object) b; + } + + + // Copy a 1D array of ErrorProp numbers (deep copy) + public static ErrorProp[] copy(ErrorProp[] a){ + int n =a.length; + ErrorProp[] b = ErrorProp.oneDarray(n); + for(int i=0; i<n; i++){ + b[i]=ErrorProp.copy(a[i]); + } + return b; + } + + // Copy a 2D array of ErrorProp numbers (deep copy) + public static ErrorProp[][] copy(ErrorProp[][] a){ + int n =a.length; + int m =a[0].length; + ErrorProp[][] b = ErrorProp.twoDarray(n, m); + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + b[i][j]=ErrorProp.copy(a[i][j]); + } + } + return b; + } + + // ADDITION + // Add two ErrorProp numbers with correlation [instance method] + public ErrorProp plus(ErrorProp a, double corrCoeff){ + ErrorProp c = new ErrorProp(); + c.value=a.value+this.value; + c.error = hypotWithCov(a.error, this.error, corrCoeff); + return c; + } + + // Add two ErrorProp numbers with correlation [static method] + public static ErrorProp plus(ErrorProp a, ErrorProp b, double corrCoeff){ + ErrorProp c = new ErrorProp(); + c.value=a.value+b.value; + c.error = hypotWithCov(a.error, b.error, corrCoeff); + return c; + } + + //Add a ErrorProp number to this ErrorProp number with no, i.e. zero, correlation [instance method] + // this ErrorProp number remains unaltered + public ErrorProp plus(ErrorProp a ){ + ErrorProp b = new ErrorProp(); + b.value = this.value + a.value; + b.error = hypotWithCov(a.error, this.error, 0.0D); + return b; + } + + // Add two ErrorProp numbers with no, i.e. zero, correlation term [static method] + public static ErrorProp plus(ErrorProp a, ErrorProp b){ + ErrorProp c = new ErrorProp(); + c.value=a.value+b.value; + c.error = hypotWithCov(a.error, b.error, 0.0D); + return c; + } + + // Add an error free double number to this ErrorProp number [instance method] + // this ErrorProp number remains unaltered + public ErrorProp plus(double a ){ + ErrorProp b = new ErrorProp(); + b.value = this.value + a; + b.error = Math.abs(this.error); + return b; + } + + //Add a ErrorProp number to an error free double [static method] + public static ErrorProp plus(double a, ErrorProp b){ + ErrorProp c = new ErrorProp(); + c.value=a+b.value; + c.error=Math.abs(b.error); + return c; + } + + //Add an error free double number to an error free double and return sum as ErrorProp [static method] + public static ErrorProp plus(double a, double b){ + ErrorProp c = new ErrorProp(); + c.value=a+b; + c.error=0.0D; + return c; + } + + + // Add a ErrorProp number to this ErrorProp number and replace this with the sum + // with correlation term + public void plusEquals(ErrorProp a, double corrCoeff){ + this.value+=a.value; + this.error = hypotWithCov(a.error, this.error, corrCoeff); + } + + // Add a ErrorProp number to this ErrorProp number and replace this with the sum + // with no, i.e. zero, correlation term + public void plusEquals(ErrorProp a){ + this.value+=a.value; + this.error = Math.sqrt(a.error*a.error + this.error*this.error); + this.error = hypotWithCov(a.error, this.error, 0.0D); + } + + //Add double number to this ErrorProp number and replace this with the sum + public void plusEquals(double a ){ + this.value+=a; + this.error=Math.abs(this.error); + } + + // SUBTRACTION + // Subtract an ErrorProp number from this ErrorProp number with correlation [instance method] + // this ErrorProp number remains unaltered + public ErrorProp minus(ErrorProp a, double corrCoeff){ + ErrorProp c = new ErrorProp(); + c.value=this.value-a.value; + c.error = hypotWithCov(this.error, a.error, -corrCoeff); + return c; + } + + // Subtract ErrorProp number b from ErrorProp number a with correlation [static method] + public static ErrorProp minus(ErrorProp a, ErrorProp b, double corrCoeff){ + ErrorProp c = new ErrorProp(); + c.value=a.value-b.value; + c.error = hypotWithCov(a.error, b.error, -corrCoeff); + return c; + } + + // Subtract a ErrorProp number from this ErrorProp number with no, i.e. zero, correlation [instance method] + // this ErrorProp number remains unaltered + public ErrorProp minus(ErrorProp a ){ + ErrorProp b = new ErrorProp(); + b.value = this.value - a.value; + b.error = hypotWithCov(a.error, this.error, 0.0D); + return b; + } + + // Subtract ErrorProp number b from ErrorProp number a with no, i.e. zero, correlation term [static method] + public static ErrorProp minus(ErrorProp a, ErrorProp b){ + ErrorProp c = new ErrorProp(); + c.value=a.value-b.value; + c.error = hypotWithCov(a.error, b.error, 0.0D); + return c; + } + + // Subtract an error free double number from this ErrorProp number [instance method] + // this ErrorProp number remains unaltered + public ErrorProp minus(double a ){ + ErrorProp b = new ErrorProp(); + b.value = this.value - a; + b.error = Math.abs(this.error); + return b; + } + + // Subtract a ErrorProp number b from an error free double a [static method] + public static ErrorProp minus(double a, ErrorProp b){ + ErrorProp c = new ErrorProp(); + c.value=a-b.value; + c.error=Math.abs(b.error); + return c; + } + + //Subtract an error free double number b from an error free double a and return sum as ErrorProp [static method] + public static ErrorProp minus(double a, double b){ + ErrorProp c = new ErrorProp(); + c.value=a-b; + c.error=0.0D; + return c; + } + + // Subtract a ErrorProp number to this ErrorProp number and replace this with the sum + // with correlation term + public void minusEquals(ErrorProp a, double corrCoeff){ + this.value-=a.value; + this.error = hypotWithCov(a.error, this.error, -corrCoeff); + } + + // Subtract a ErrorProp number from this ErrorProp number and replace this with the sum + // with no, i.e. zero, correlation term + public void minusEquals(ErrorProp a){ + this.value-=a.value; + this.error = hypotWithCov(a.error, this.error, 0.0D); + } + + // Subtract a double number from this ErrorProp number and replace this with the sum + public void minusEquals(double a){ + this.value-=a; + this.error=Math.abs(this.error); + } + + // MULTIPLICATION + //Multiply two ErrorProp numbers with correlation [instance method] + public ErrorProp times(ErrorProp a, double corrCoeff){ + ErrorProp c = new ErrorProp(); + double cov = corrCoeff*a.error*this.error; + c.value=a.value*this.value; + if(a.value==0.0D){ + c.error=a.error*this.value; + } + else{ + if(this.value==0.0D){ + c.error=this.error*a.value; + } + else{ + c.error = Math.abs(c.value)*hypotWithCov(a.error/a.value, this.error/this.value, corrCoeff); + } + } + return c; + } + + //Multiply this ErrorProp number by a ErrorProp number [instance method] + // with no, i.e. zero, correlation + // this ErrorProp number remains unaltered + public ErrorProp times(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value=this.value*a.value; + if(a.value==0.0D){ + b.error=a.error*this.value; + } + else{ + if(this.value==0.0D){ + b.error=this.error*a.value; + } + else{ + b.error = Math.abs(b.value)*hypotWithCov(a.error/a.value, this.error/this.value, 0.0D); + } + } + return b; + } + + //Multiply this ErrorProp number by a double [instance method] + // this ErrorProp number remains unaltered + public ErrorProp times(double a){ + ErrorProp b = new ErrorProp(); + b.value=this.value*a; + b.error=Math.abs(this.error*a); + return b; + } + + + //Multiply two ErrorProp numbers with correlation [static method] + public static ErrorProp times(ErrorProp a, ErrorProp b, double corrCoeff){ + ErrorProp c = new ErrorProp(); + double cov = corrCoeff*a.error*b.error; + c.value=a.value*b.value; + if(a.value==0.0D){ + c.error=a.error*b.value; + } + else{ + if(b.value==0.0D){ + c.error=b.error*a.value; + } + else{ + c.error = Math.abs(c.value)*hypotWithCov(a.error/a.value, b.error/b.value, corrCoeff); + } + } + return c; + } + + //Multiply two ErrorProp numbers with no, i.e. zero, correlation [static method] + public static ErrorProp times(ErrorProp a, ErrorProp b){ + ErrorProp c = new ErrorProp(); + c.value=a.value*b.value; + if(a.value==0.0D){ + c.error=a.error*b.value; + } + else{ + if(b.value==0.0D){ + c.error=b.error*a.value; + } + else{ + c.error = Math.abs(c.value)*hypotWithCov(a.error/a.value, b.error/b.value, 0.0D); + } + } + return c; + } + + //Multiply a double by a ErrorProp number [static method] + public static ErrorProp times(double a, ErrorProp b){ + ErrorProp c = new ErrorProp(); + c.value=a*b.value; + c.error=Math.abs(a*b.error); + return c; + } + + //Multiply a double number by a double and return product as ErrorProp [static method] + public static ErrorProp times(double a, double b){ + ErrorProp c = new ErrorProp(); + c.value=a*b; + c.error=0.0; + return c; + } + + //Multiply this ErrorProp number by an ErrorProp number and replace this by the product + // with correlation + public void timesEquals(ErrorProp a, double corrCoeff){ + ErrorProp b = new ErrorProp(); + double cov = corrCoeff*this.error*a.error; + b.value = this.value*a.value; + if(a.value==0.0D){ + b.error=a.error*this.value; + } + else{ + if(this.value==0.0D){ + b.error=this.error*a.value; + } + else{ + b.error = Math.abs(b.value)*hypotWithCov(a.error/a.value, this.error/this.value, corrCoeff); + } + } + + this.value = b.value; + this.error = b.error; + } + + //Multiply this ErrorProp number by an ErrorProp number and replace this by the product + // with no, i.e. zero, correlation + public void timesEquals(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = this.value*a.value; + if(a.value==0.0D){ + b.error=a.error*this.value; + } + else{ + if(this.value==0.0D){ + b.error=this.error*a.value; + } + else{ + b.error = Math.abs(b.value)*hypotWithCov(a.error/a.value, this.error/this.value, 0.0D); + } + } + + this.value = b.value; + this.error = b.error; + } + + //Multiply this ErrorProp number by a double and replace this by the product + public void timesEquals(double a){ + this.value=this.value*a; + this.error=Math.abs(this.error*a); + } + + // DIVISION + // Division of this ErrorProp number by a ErrorProp number [instance method] + // this ErrorProp number remains unaltered + // with correlation + public ErrorProp over(ErrorProp a, double corrCoeff){ + ErrorProp c = new ErrorProp(); + c.value = this.value/a.value; + if(this.value==0.0D){ + c.error=this.error*a.value; + } + else{ + c.error = Math.abs(c.value)*hypotWithCov(this.error/this.value, a.error/a.value, -corrCoeff); + } + return c; + } + + // Division of two ErrorProp numbers a/b [static method] + // with correlation + public static ErrorProp over(ErrorProp a, ErrorProp b, double corrCoeff){ + ErrorProp c = new ErrorProp(); + c.value = a.value/b.value; + if(a.value==0.0D){ + c.error=a.error*b.value; + } + else{ + c.error = Math.abs(c.value)*hypotWithCov(a.error/a.value, b.error/b.value, -corrCoeff); + } + return c; + } + + // Division of this ErrorProp number by a ErrorProp number [instance method] + // this ErrorProp number remains unaltered + // with no, i.e. zero, correlation + public ErrorProp over(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = this.value/a.value; + b.error = Math.abs(b.value)*hypotWithCov(a.error/a.value, this.error/this.value, 0.0); + if(this.value==0.0D){ + b.error=this.error*b.value; + } + else{ + b.error = Math.abs(b.value)*hypotWithCov(a.error/a.value, this.error/this.value, 0.0); + } + return b; + } + + // Division of two ErrorProp numbers a/b [static method] + // with no, i.e. zero, correlation + public static ErrorProp over(ErrorProp a, ErrorProp b){ + ErrorProp c = new ErrorProp(); + c.value = a.value/b.value; + if(a.value==0.0D){ + c.error=a.error*b.value; + } + else{ + c.error = Math.abs(c.value)*hypotWithCov(a.error/a.value, b.error/b.value, 0.0D); + } + + return c; + } + + //Division of this ErrorProp number by a double [instance method] + // this ErrorProp number remains unaltered + public ErrorProp over(double a){ + ErrorProp b = new ErrorProp(); + b.value=this.value/a; + b.error=Math.abs(this.error/a); + return b; + } + + + // Division of a double, a, by a ErrorProp number, b [static method] + public static ErrorProp over(double a, ErrorProp b){ + ErrorProp c = new ErrorProp(); + c.value = a/b.value; + c.error = Math.abs(a*b.error/(b.value*b.value)); + return c; + } + + // Divide a double number by a double and return quotient as ErrorProp [static method] + public static ErrorProp over(double a, double b){ + ErrorProp c = new ErrorProp(); + c.value=a/b; + c.error=0.0; + return c; + } + + // Division of this ErrorProp number by a ErrorProp number and replace this by the quotient + // with no, i.r. zero, correlation + public void overEquals(ErrorProp b){ + ErrorProp c = new ErrorProp(); + c.value = this.value/b.value; + if(this.value==0.0D){ + c.error=this.error*b.value; + } + else{ + c.error = Math.abs(c.value)*hypotWithCov(this.error/this.value, b.error/b.value, 0.0D); + } + this.value = c.value; + this.error = c.error; + } + + // Division of this ErrorProp number by a ErrorProp number and replace this by the quotient + // with correlation + public void overEquals(ErrorProp b, double corrCoeff){ + ErrorProp c = new ErrorProp(); + c.value = this.value/b.value; + if(this.value==0.0D){ + c.error=this.error*b.value; + } + else{ + c.error = Math.abs(c.value)*hypotWithCov(this.error/this.value, b.error/b.value, -corrCoeff); + } + this.value = c.value; + this.error = c.error; + } + + //Division of this ErrorProp number by a double and replace this by the quotient + public void overEquals(double a){ + this.value=this.value/a; + this.error=Math.abs(this.error/a); + } + + // RECIPROCAL + // Returns the reciprocal (1/a) of a ErrorProp number (a) [instance method] + public ErrorProp inverse(){ + ErrorProp b = ErrorProp.over(1.0D, this); + return b; + } + + // Returns the reciprocal (1/a) of a ErrorProp number (a) [static method] + public static ErrorProp inverse(ErrorProp a){ + ErrorProp b = ErrorProp.over(1.0, a); + return b; + } + + //FURTHER MATHEMATICAL FUNCTIONS + + // Returns the length of the hypotenuse of a and b i.e. sqrt(a*a + b*b) + // where a and b are ErrorProp [without unecessary overflow or underflow] + // with correlation + public static ErrorProp hypot(ErrorProp a, ErrorProp b, double corrCoeff){ + ErrorProp c = new ErrorProp(); + c.value = Fmath.hypot(a.value, b.value); + c.error = Math.abs(hypotWithCov(a.error*a.value, b.error*b.value, corrCoeff)/c.value); + return c; + } + + // Returns the length of the hypotenuse of a and b i.e. sqrt(a*a + b*b) + // where a and b are ErrorProp [without unecessary overflow or underflow] + // with no, i.e. zero, correlation + public static ErrorProp hypot(ErrorProp a, ErrorProp b){ + ErrorProp c = new ErrorProp(); + c.value = Fmath.hypot(a.value, b.value); + c.error = Math.abs(hypotWithCov(a.error*a.value, b.error*b.value, 0.0D)/c.value); + return c; + } + + //Absolute value [static method] + public static ErrorProp abs(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Math.abs(a.value); + b.error = Math.abs(a.error); + return b; + } + + //Absolute value [instance method] + public ErrorProp abs(){ + ErrorProp b = new ErrorProp(); + b.value = Math.abs(this.value); + b.error = Math.abs(this.error); + return b; + } + + // Exponential + public static ErrorProp exp(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Math.exp(a.value); + b.error = Math.abs(b.value*a.error); + return b; + } + + // Natural log + public static ErrorProp log(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Math.log(a.value); + b.error = Math.abs(a.error/a.value); + return b; + } + + // log to base 10 + public static ErrorProp log10(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Fmath.log10(a.value); + b.error = Math.abs(a.error/(a.value*Math.log(10.0D))); + return b; + } + + //Roots + // Square root + public static ErrorProp sqrt(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Math.sqrt(a.value); + b.error = Math.abs(a.error/(2.0D*a.value)); + return b; + } + + // The nth root (n = integer > 1) + public static ErrorProp nthRoot(ErrorProp a, int n){ + if(n==0)throw new ArithmeticException("Division by zero (n = 0 - infinite root) attempted in ErrorProp.nthRoot"); + ErrorProp b = new ErrorProp(); + b.value = Math.pow(a.value, 1/n); + b.error = Math.abs(a.error*Math.pow(a.value, 1/n-1)/((double)n)); + return b; + } + + //Powers + //Square [instance method] + public ErrorProp square(){ + ErrorProp a = new ErrorProp(this.value, this.error); + return a.times(a, 1.0D); + } + + //Square [static method] + public static ErrorProp square(ErrorProp a){ + return a.times(a,1.0D); + } + + // returns an ErrorProp number raised to an error free power + public static ErrorProp pow(ErrorProp a, double b){ + ErrorProp c = new ErrorProp(); + c.value = Math.pow(a.value, b); + c.error = Math.abs(b*Math.pow(a.value, b-1.0)); + return c; + } + + // returns an error free number raised to an ErrorProp power + public static ErrorProp pow(double a, ErrorProp b){ + ErrorProp c = new ErrorProp(); + c.value = Math.pow(a, b.value); + c.error = Math.abs(c.value*Math.log(a)*b.error); + return c; + } + + // returns a ErrorProp number raised to a ErrorProp power + // with correlation + public static ErrorProp pow(ErrorProp a, ErrorProp b, double corrCoeff){ + ErrorProp c = new ErrorProp(); + c.value = Math.pow(a.value, b.value); + c.error = hypotWithCov(a.error*b.value*Math.pow(a.value, b.value-1.0), b.error*Math.log(a.value)*Math.pow(a.value, b.value), corrCoeff); + return c; + } + + // returns a ErrorProp number raised to a ErrorProp power + // with zero correlation + public static ErrorProp pow(ErrorProp a, ErrorProp b){ + ErrorProp c = new ErrorProp(); + c.value = Math.pow(a.value, b.value); + c.error = hypotWithCov(a.error*b.value*Math.pow(a.value, b.value-1.0), b.error*Math.log(a.value)*Math.pow(a.value, b.value), 0.0D); + return c; + } + + // ErrorProp trigonometric functions + + //Sine of an ErrorProp number + public static ErrorProp sin(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Math.sin(a.value); + b.error = Math.abs(a.error*Math.cos(a.value)); + return b; + } + + //Cosine of an ErrorProp number + public static ErrorProp cos(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Math.cos(a.value); + b.error = Math.abs(a.error*Math.sin(a.value)); + return b; + } + + //Tangent of an ErrorProp number + public static ErrorProp tan(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Math.tan(a.value); + b.error = Math.abs(a.error*Fmath.square(Fmath.sec(a.value))); + return b; + } + + //Hyperbolic sine of a ErrorProp number + public static ErrorProp sinh(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Fmath.sinh(a.value); + b.error = Math.abs(a.error*Fmath.cosh(a.value)); + return b; + } + + //Hyperbolic cosine of a ErrorProp number + public static ErrorProp cosh(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Fmath.cosh(a.value); + b.error = Math.abs(a.error*Fmath.sinh(a.value)); + return b; + } + + //Hyperbolic tangent of a ErrorProp number + public static ErrorProp tanh(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Fmath.tanh(a.value); + b.error = Math.abs(a.error*Fmath.square(Fmath.sech(a.value))); + return b; + } + + //Inverse sine of a ErrorProp number + public static ErrorProp asin(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Math.asin(a.value); + b.error = Math.abs(a.error/Math.sqrt(1.0D - a.value*a.value)); + return b; + } + + //Inverse cosine of a ErrorProp number + public static ErrorProp acos(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Math.acos(a.value); + b.error = Math.abs(a.error/Math.sqrt(1.0D - a.value*a.value)); + return b; + } + + //Inverse tangent of a ErrorProp number + public static ErrorProp atan(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Math.atan(a.value); + b.error = Math.abs(a.error/(1.0D + a.value*a.value)); + return b; + } + + //Inverse tangent (atan2) of a ErrorProp number - no correlation + public static ErrorProp atan2(ErrorProp a, ErrorProp b){ + ErrorProp c = new ErrorProp(); + ErrorProp d = a.over(b); + c.value = Math.atan2(a.value, b.value); + c.error = Math.abs(d.error/(1.0D + d.value*d.value)); + return c; + } + //Inverse tangent (atan2) of a ErrorProp number - correlation + public static ErrorProp atan2(ErrorProp a, ErrorProp b, double rho){ + ErrorProp c = new ErrorProp(); + ErrorProp d = a.over(b, rho); + c.value = Math.atan2(a.value, b.value); + c.error = Math.abs(d.error/(1.0D + d.value*d.value)); + return c; + } + + //Inverse hyperbolic sine of a ErrorProp number + public static ErrorProp asinh(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Fmath.asinh(a.value); + b.error = Math.abs(a.error/Math.sqrt(a.value*a.value + 1.0D)); + return b; + } + + //Inverse hyperbolic cosine of a ErrorProp number + public static ErrorProp acosh(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Fmath.acosh(a.value); + b.error = Math.abs(a.error/Math.sqrt(a.value*a.value - 1.0D)); + return b; + } + + //Inverse hyperbolic tangent of a ErrorProp number + public static ErrorProp atanh(ErrorProp a){ + ErrorProp b = new ErrorProp(); + b.value = Fmath.atanh(a.value); + b.error = Math.abs(a.error/(1.0D - a.value*a.value)); + return b; + } + + // SOME USEFUL NUMBERS + // returns the number zero (0) with zero error + public static ErrorProp zero(){ + ErrorProp c = new ErrorProp(); + c.value=0.0D; + c.error=0.0D; + return c; + } + + // returns the number one (+1) with zero error + public static ErrorProp plusOne(){ + ErrorProp c = new ErrorProp(); + c.value=1.0D; + c.error=0.0D; + return c; + } + + // returns the number minus one (-1) with zero error + public static ErrorProp minusOne(){ + ErrorProp c = new ErrorProp(); + c.value=-1.0D; + c.error=0.0D; + return c; + } + + // Private methods + // Safe calculation of sqrt(a*a + b*b + 2*r*a*b) + private static double hypotWithCov(double a, double b, double r){ + double pre=0.0D, ratio=0.0D, sgn=0.0D; + + if(a==0.0D && b==0.0D)return 0.0D; + if(Math.abs(a)>Math.abs(b)){ + pre = Math.abs(a); + ratio = b/a; + sgn = Fmath.sign(a); + } + else{ + pre = Math.abs(b); + ratio = a/b; + sgn = Fmath.sign(b); + } + return pre*Math.sqrt(1.0D + ratio*(ratio + 2.0D*r*sgn)); + } +} + diff --git a/src/main/java/flanagan/analysis/PCA.java b/src/main/java/flanagan/analysis/PCA.java new file mode 100755 index 0000000000000000000000000000000000000000..acaba0165d6e751cdca3ae6e195abb2e873cc3b0 --- /dev/null +++ b/src/main/java/flanagan/analysis/PCA.java @@ -0,0 +1,1758 @@ +/* +* CLASS: PCA +* +* USAGE: Principlal Component Analysis +* +* This is a subclass of the superclass Scores +* +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: October 2008 +* AMENDED: 17-18 October 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* http://www.ee.ucl.ac.uk/~mflanaga/java/PCA.html +* +* Copyright (c) 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + + +package flanagan.analysis; + +import java.util.*; +import java.text.*; +import java.awt.*; + +import flanagan.math.*; +import flanagan.io.*; +import flanagan.analysis.*; +import flanagan.plot.*; + + +public class PCA extends Scores{ + + private Matrix data = null; // data as row per item as a Matrix + private Matrix dataMinusMeans = null; // data with row means subtracted as row per item as a Matrix + private Matrix dataMinusMeansTranspose = null; // data with row means subtracted as row per item as a Matrix + private Matrix covarianceMatrix = null; // variance-covariance Matrix + private Matrix correlationMatrix = null; // variance-covariance Matrix + + private double[] eigenValues = null; // eigenvalues + private double[] orderedEigenValues = null; // eigenvalues sorted into a descending order + private int[] eigenValueIndices = null; // indices of the eigenvalues before sorting into a descending order + private double eigenValueTotal = 0.0; // total of all eigen values; + + private double[] rotatedEigenValues = null; // scaled rotated eigenvalues + private double[] usRotatedEigenValues = null; // unscaled rotated eigenvalues + + + private int nMonteCarlo = 200; // number of Monte Carlo generated eigenvalue calculations + private double[][] randomEigenValues = null; // Monte Carlo generated eigenvalues + private double[] randomEigenValuesMeans = null; // means of the Monte Carlo generated eigenvalues + private double[] randomEigenValuesSDs = null; // standard deviations of the Monte Carlo generated eigenvalues + private double[] randomEigenValuesPercentiles = null; // percentiles of the Monte Carlo generated eigenvalues + private double percentile = 95.0; // percentile used in parallel analysis + private boolean gaussianDeviates = false; // = false: uniform random deviates used in Monte Carlo + // = true: Gaussian random deviates used in Monte Carlo + private double[] proportionPercentage = null; // eigenvalues expressesed as percentage of total + private double[] cumulativePercentage = null; // cumulative values of the eigenvalues expressesed as percentage of total + private double[] rotatedProportionPercentage = null; // scaled rotated eigenvalues expressesed as percentage of unrotated total + private double[] rotatedCumulativePercentage = null; // scaled rotated cumulative values of the eigenvalues expressesed as percentage of unrotated total + + private double[][] eigenVectorsAsColumns = null; // eigenvectors as columns + private double[][] eigenVectorsAsRows = null; // eigenvectors as rows + + private double[][] orderedEigenVectorsAsColumns = null; // eigenvectors, as columns, arranged to match a descending order of eigenvalues + private double[][] orderedEigenVectorsAsRows = null; // eigenvectors, as rows, arranged to match a descending order of eigenvalues + + private double[][] loadingFactorsAsColumns = null; // loading factors as column per eigenvalue + private double[][] loadingFactorsAsRows = null; // loading factors as row per eigenvalue + + private double[][] rotatedLoadingFactorsAsColumns = null; // scaled rotated loading factors as column per eigenvalue + private double[][] rotatedLoadingFactorsAsRows = null; // scaled rotated loading factors as row per eigenvalue + private double[][] usRotatedLoadingFactorsAsColumns = null; // unscaled rotated loading factors as column per eigenvalue + private double[][] usRotatedLoadingFactorsAsRows = null; // unscaled rotated loading factors as row per eigenvalue + + private double[] communalities = null; // communalities + + + private boolean covRhoOption = false; // = true: covariance matrix used + // = false: correlation matrix used + + private int greaterThanOneLimit = 0; // number of components extracted using eigenvalue greater than one + private int percentileCrossover = 0; // number of components extracted using percentile scree crossover + private int meanCrossover = 0; // number of components extracted using mean scree crossover + + private int nVarimaxMax = 1000; // maximum iterations allowed by the varimax criterion + private int nVarimax = 0; // number of iterations taken by the varimax criterion + private double varimaxTolerance = 0.0001; // tolerance for terminatiing 2 criterion iteration + + private boolean varimaxOption = true; // = true: normal varimax, i.e. comunality weighted varimax + // = false: raw varimax + private boolean pcaDone = false; // = true when PCA performed + private boolean monteCarloDone = false; // = true when parallel monte Carlo simultaion performed + private boolean rotationDone = false; // = true when rotation performed + + // CONSTRUCTOR + public PCA(){ + super.trunc = 4; + } + + // CHOICE OF MATRIX + // Use covariance matrix (default option) + public void useCovarianceMatrix(){ + this.covRhoOption = true; + } + + // Use correlation matrix (default option) + public void useCorrelationMatrix(){ + this.covRhoOption = false; + } + + // CHOICE OF VARIMAX CRITERION + // Use normal varimax rotation + public void useNormalVarimax(){ + this. varimaxOption = true; + } + + // Use raw varimax rotation + public void useRawVarimax(){ + this. varimaxOption = false; + } + + // Return varimax rotation option + public String getVarimaxOption(){ + if(this. varimaxOption){ + return "normal varimax option"; + } + else{ + return "raw varimax option"; + } + } + + // PARALLEL ANALYSIS OPTIONS + // Reset number of Monte Carlo simulations + public void setNumberOfSimulations(int nSimul){ + this.nMonteCarlo = nSimul; + } + + // Return number of Monte Carlo simulations + public int getNumberOfSimulations(){ + return this.nMonteCarlo; + } + + // Use Gaussian random deviates in MontMonte Carlo simulations + public void useGaussianDeviates(){ + this.gaussianDeviates = true; + } + + // Use uniform random deviates in MontMonte Carlo simulations + public void useUniformDeviates(){ + this.gaussianDeviates = false; + } + + // Reset percentile percentage in parallel analysis (defalut option = 95%) + public void setParallelAnalysisPercentileValue(double percent){ + this.percentile = percent; + } + + // Return percentile percentage in parallel analysis (defalut option = 95%) + public double getParallelAnalysisPercentileValue(){ + return this.percentile; + } + + // PRINCIPAL COMPONENT ANALYSIS + public void pca(){ + + if(!this.pcaDone){ + + if(this.nItems==1)throw new IllegalArgumentException("You have entered only one item - PCA is not meaningful"); + if(this.nPersons==1)throw new IllegalArgumentException("You have entered only one score or measurement source - PCA is not meaningful"); + + // Check that data is preprocessed + if(!this.dataPreprocessed)this.preprocessData(); + + // Store data as an instance of matrix + this.data = new Matrix(super.scores0); + + // Subtract row means + this.dataMinusMeans = this.data.subtractRowMeans(); + + // Transpose + this.dataMinusMeansTranspose = this.dataMinusMeans.transpose(); + + // Covariance matrix + this.covarianceMatrix = this.dataMinusMeans.times(this.dataMinusMeansTranspose); + double denom = this.nPersons; + if(!super.nFactorOption)denom -= 1.0; + this.covarianceMatrix = this.covarianceMatrix.times(1.0/denom); + + // Correlation matrix + double[][] cov = this.covarianceMatrix.getArrayCopy(); + double[][] corr = new double[this.nItems][this.nItems]; + for(int i=0; i<this.nItems; i++){ + for(int j=0; j<this.nItems; j++){ + if(i==j){ + corr[i][j] = 1.0; + } + else{ + corr[i][j] = cov[i][j]/Math.sqrt(cov[i][i]*cov[j][j]); + } + } + } + this.correlationMatrix = new Matrix(corr); + + // Choose matrix + Matrix forEigen = null; + if(covRhoOption){ + forEigen = this.covarianceMatrix; + } + else{ + forEigen = this.correlationMatrix; + } + + + // Calculate eigenvalues + this.eigenValues = forEigen.getEigenValues(); + + // Calculate ordered eigenvalues + this.orderedEigenValues = forEigen.getSortedEigenValues(); + + // Store indices of the eigenvalues before sorting into escending order + this.eigenValueIndices = forEigen.eigenValueIndices(); + + // Calculate eigenvectors + this.eigenVectorsAsColumns = forEigen.getEigenVectorsAsColumns(); + this.eigenVectorsAsRows = forEigen.getEigenVectorsAsRows(); + + // Calculate ordered eigenvectors + this.orderedEigenVectorsAsColumns = forEigen.getSortedEigenVectorsAsColumns(); + this.orderedEigenVectorsAsRows = forEigen.getSortedEigenVectorsAsRows(); + + // Express eigenvalues as percentage of total + ArrayMaths am = new ArrayMaths(this.orderedEigenValues); + double total = am.sum(); + am = am.times(100.0/total); + this.proportionPercentage = am.array(); + + // Calculate cumulative percentage + this.cumulativePercentage = new double[this.nItems]; + this.cumulativePercentage[0] = this.proportionPercentage[0]; + this.eigenValueTotal = 0.0; + for(int i=1; i<this.nItems; i++){ + this.cumulativePercentage[i] = this.cumulativePercentage[i-1] + this.proportionPercentage[i]; + this.eigenValueTotal += this.eigenValues[i]; + } + + + // Calculate 'eigenvalue less than or equal to one' extraction limit + boolean test = true; + int counter = 0; + while(test){ + if(this.orderedEigenValues[counter]<1.0){ + this.greaterThanOneLimit = counter; + test = false; + } + else{ + counter++; + if(counter==this.nItems){ + this.greaterThanOneLimit = counter; + test = false; + } + } + } + + // Calculate loading factors + this.loadingFactorsAsColumns = new double[this.nItems][this.nItems]; + this.loadingFactorsAsRows = new double[this.nItems][this.nItems]; + for(int i=0; i<this.nItems; i++){ + for(int j=0; j<this.nItems; j++){ + this.loadingFactorsAsColumns[i][j] = this.orderedEigenVectorsAsColumns[i][j]*Math.sqrt(Math.abs(this.orderedEigenValues[j])); + this.loadingFactorsAsRows[i][j] = this.orderedEigenVectorsAsRows[i][j]*Math.sqrt(Math.abs(this.orderedEigenValues[i])); + } + } + + // Calculate communalities + this.communalities = new double[this.nItems]; + for(int k=0; k<this.nItems; k++){ + double sum = 0.0; + for(int j=0; j<this.nItems; j++)sum += loadingFactorsAsRows[j][k]*loadingFactorsAsRows[j][k]; + this.communalities[k] = sum; + } + + } + + this.pcaDone = true; + + } + + // MonteCarlo Eigenvalues + public void monteCarlo(){ + if(!pcaDone)this.pca(); + double[] rowMeans = super.rawItemMeans(); + double[] rowSDs = super.rawItemStandardDeviations(); + double[][] randomData = new double[super.nItems][super.nPersons]; + this.randomEigenValues = new double[this.nMonteCarlo][super.nItems]; + PsRandom rr = new PsRandom(); + for(int i=0; i<this.nMonteCarlo; i++){ + for(int j=0; j<this.nItems; j++){ + if(this.gaussianDeviates){ + randomData[j] = rr.gaussianArray(rowMeans[j], rowSDs[j], super.nPersons); + } + else{ + randomData[j] = rr.doubleArray(super.nPersons); + randomData[j] = Stat.scale(randomData[j], rowMeans[j], rowSDs[j]); + } + } + PCA pca = new PCA(); + if(this.covRhoOption){ + pca.useCovarianceMatrix(); + } + else{ + pca.useCorrelationMatrix(); + } + pca.enterScoresAsRowPerItem(randomData); + this.randomEigenValues[i] = pca.orderedEigenValues(); + + } + Matrix mat = new Matrix(randomEigenValues); + this.randomEigenValuesMeans = mat.columnMeans(); + this.randomEigenValuesSDs = mat.columnStandardDeviations(); + this.randomEigenValuesPercentiles = new double[this.nItems]; + + int pIndex1 = (int)Math.ceil(this.nMonteCarlo*this.percentile/100.0); + int pIndex2 = pIndex1-1; + double factor = (this.percentile*this.nMonteCarlo/100.0 - pIndex2); + pIndex1--; + pIndex2--; + for(int j=0; j<this.nItems; j++){ + double[] ordered = new double[this.nMonteCarlo]; + for(int k=0; k<this.nMonteCarlo; k++)ordered[k] = this.randomEigenValues[k][j]; + ArrayMaths am = new ArrayMaths(ordered); + am = am.sort(); + ordered = am.array(); + this.randomEigenValuesPercentiles[j] = ordered[pIndex2] + factor*(ordered[pIndex1] - ordered[pIndex2]); + } + + // Calculate percentile crossover extraction limit + boolean test = true; + int counter = 0; + while(test){ + if(this.orderedEigenValues[counter]<=this.randomEigenValuesPercentiles[counter]){ + this.percentileCrossover = counter; + test = false; + } + else{ + counter++; + if(counter==this.nItems){ + this.percentileCrossover = counter; + test = false; + } + } + } + + // Calculate mean crossover extraction limit + test = true; + counter = 0; + while(test){ + if(this.orderedEigenValues[counter]<=this.randomEigenValuesMeans[counter]){ + this.meanCrossover = counter; + test = false; + } + else{ + counter++; + if(counter==this.nItems){ + this.meanCrossover = counter; + test = false; + } + } + } + + this.monteCarloDone = true; + + } + + // SCREE PLOTS + // Scree plot of data alone + public void screePlotDataAlone(){ + if(!this.pcaDone)this.pca(); + + // Create X-axis data array + double[] components = new double[super.nItems]; + for(int i=0; i<this.nItems; i++)components[i] = i+1; + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(components, this.orderedEigenValues); + pg.setGraphTitle("Principal Component Analysis Scree Plot"); + pg.setXaxisLegend("Component"); + pg.setYaxisLegend("Eigenvalues"); + pg.setLine(3); + pg.setPoint(1); + pg.plot(); + } + + + // Scree plot eigenvalues plus plot of Monte Carlo percentiles, means and standard deviations + public void screePlot(){ + if(!this.pcaDone)this.pca(); + if(!this.monteCarloDone)this.monteCarlo(); + + // Create plotting data array + double[][] plotData = new double[6][super.nItems]; + double[] components = new double[super.nItems]; + for(int i=0; i<this.nItems; i++)components[i] = i+1; + plotData[0] = components; + plotData[1] = this.orderedEigenValues; + plotData[2] = components; + plotData[3] = this.randomEigenValuesPercentiles; + plotData[4] = components; + plotData[5] = this.randomEigenValuesMeans; + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(plotData); + pg.setErrorBars(2, this.randomEigenValuesSDs); + if(this.gaussianDeviates){ + pg.setGraphTitle("Principal Component Analysis Scree Plot with Parallel Analysis using Gaussian deviates (" + nMonteCarlo + " simulations)"); + } + else{ + pg.setGraphTitle("Principal Component Analysis Scree Plot with Parallel Analysis using uniform deviates (" + nMonteCarlo + " simulations)"); + } + pg.setGraphTitle2("Closed squares - data eigenvalues; open circles = Monte Carlo eigenvalue " + this.percentile + "% percentiles; error bars = standard deviations about the Monte carlo means (crosses)"); + pg.setXaxisLegend("Component"); + pg.setYaxisLegend("Eigenvalue"); + int[] line = {3, 0, 3}; + pg.setLine(line); + int point[] = {5, 1, 7}; + pg.setPoint(point); + pg.plot(); + } + + + // VARIMAX ROTATION + // Set varimax tolerance + public void setVarimaxTolerance(double tolerance){ + this.varimaxTolerance = tolerance; + } + + // Set varimax maximum number of iterations + public void setVarimaxMaximumIterations(int max){ + this.nVarimaxMax = max; + } + + // Get varimax number of iterations + public int getVarimaxIterations(){ + return this.nVarimax; + } + + + // Varimax rotation: option set by default + public void varimaxRotation(int nFactors){ + if(!this.pcaDone)this.pca(); + if(this.varimaxOption){ + this.normalVarimaxRotation(nFactors); + } + else{ + this.rawVarimaxRotation(nFactors); + } + } + + // Varimax rotation: option set by default + // only raw option possible + public void varimaxRotation(double[][] loadingFactorMatrix){ + if(this.varimaxOption)System.out.println("Method varimaxRotation: communality weights not supplied - raw varimax option used"); + this.rawVarimaxRotationInHouse(loadingFactorMatrix); + } + + // Varimax rotation: option set by default + public void varimaxRotation(double[][] loadingFactorMatrix, double[] communalityWeights){ + if(this.varimaxOption){ + this.normalVarimaxRotationInHouse(loadingFactorMatrix, communalityWeights); + } + else{ + System.out.println("Method varimaxRotation: raw varimax option chosen, supplied communality weights ignored"); + this.rawVarimaxRotationInHouse(loadingFactorMatrix); + } + } + + + // Raw varimax rotation + public void rawVarimaxRotation(int nFactors){ + if(!this.pcaDone)this.pca(); + double[][] loadingFactorMatrix = new double[nFactors][this.nItems]; + for(int i = 0; i<nFactors; i++)loadingFactorMatrix[i] = this.loadingFactorsAsRows[i]; + double[] communalityWeights = new double[this.nItems]; + for(int i = 0; i<this.nItems; i++)communalityWeights[i] = 1.0; + this.normalVarimaxRotationInHouse(loadingFactorMatrix, communalityWeights); + } + + // Raw varimax rotation + private void rawVarimaxRotationInHouse(double[][] loadingFactorMatrix){ + double[] communalityWeights = new double[this.nItems]; + for(int i = 0; i<this.nItems; i++)communalityWeights[i] = 1.0; + this.normalVarimaxRotationInHouse(loadingFactorMatrix, communalityWeights); + } + + // Normal varimax rotation + public void normalVarimaxRotation(int nFactors){ + if(!this.pcaDone)this.pca(); + double[][] loadingFactorMatrix = new double[nFactors][this.nItems]; + for(int i = 0; i<nFactors; i++)loadingFactorMatrix[i] = this.loadingFactorsAsRows[i]; + double[] communalityWeights = new double[this.nItems]; + for(int i = 0; i<nItems; i++){ + communalityWeights[i] = 0.0; + for(int j = 0; j<nFactors; j++)communalityWeights[i] += loadingFactorMatrix[j][i]*loadingFactorMatrix[j][i]; + } + this.normalVarimaxRotationInHouse(loadingFactorMatrix, communalityWeights); + } + + // Normal varimax rotation - also used by raw varimax rotation with weights set to unity + private void normalVarimaxRotationInHouse(double[][] loadingFactorMatrix, double[] communalityWeights){ + if(!this.pcaDone)this.pca(); + int nRows = loadingFactorMatrix.length; + int nColumns = loadingFactorMatrix[0].length; + this.usRotatedLoadingFactorsAsRows = new double[nRows][nColumns]; + this.rotatedLoadingFactorsAsRows = new double[nRows][nColumns]; + this.usRotatedEigenValues = new double[nRows]; + this.rotatedEigenValues = new double[nRows]; + this.rotatedProportionPercentage= new double[nRows]; + this.rotatedCumulativePercentage= new double[nRows]; + + // Calculate weights and normalize the loading factors + for(int j = 0; j<nColumns; j++)communalityWeights[j] = Math.sqrt(communalityWeights[j]); + for(int i = 0; i<nRows; i++){ + for(int j = 0; j<nColumns; j++){ + loadingFactorMatrix[i][j] /= communalityWeights[j]; + this.usRotatedLoadingFactorsAsRows[i][j] = loadingFactorMatrix[i][j]; + } + } + + // Loop through pairwise rotations until varimax function maximised + double va = PCA.varimaxCriterion(this.usRotatedLoadingFactorsAsRows); + double vaLast = 0; + double angle = 0; + boolean test = true; + this.nVarimax = 0; + while(test){ + for(int i=0; i<nRows-1; i++){ + for(int j=i+1; j<nRows; j++){ + angle = PCA.varimaxAngle(this.usRotatedLoadingFactorsAsRows, i, j); + this.usRotatedLoadingFactorsAsRows = PCA.singleRotation(this.usRotatedLoadingFactorsAsRows, i, j, angle); + va = PCA.varimaxCriterion(this.usRotatedLoadingFactorsAsRows); + } + } + if(Math.abs(va - vaLast)<this.varimaxTolerance){ + test=false; + } + else{ + vaLast = va; + this.nVarimax++; + if(this.nVarimax>nVarimaxMax){ + test=false; + System.out.println("Method varimaxRotation: maximum iterations " + nVarimaxMax + "exceeded"); + System.out.println("Current values returned"); + } + } + + } + + // undo normalization of rotated loading factors + this.usRotatedLoadingFactorsAsColumns = new double[nColumns][nRows]; + for(int i=0; i<nRows; i++){ + for(int j=0; j<nColumns; j++){ + this.usRotatedLoadingFactorsAsRows[i][j] *= communalityWeights[j]; + this.usRotatedLoadingFactorsAsColumns[j][i] = this.usRotatedLoadingFactorsAsRows[i][j]; + loadingFactorMatrix[i][j] *= communalityWeights[j]; + } + } + + // Rotated eigenvalues + double usRotatedEigenValueTotal = 0.0; + double unRotatedEigenValueTotal = 0.0; + for(int i=0; i<nRows; i++){ + this.usRotatedEigenValues[i] = 0.0; + for(int j=0; j<nColumns; j++){ + this.usRotatedEigenValues[i] += this.usRotatedLoadingFactorsAsRows[i][j]*this.usRotatedLoadingFactorsAsRows[i][j]; + } + usRotatedEigenValueTotal += this.usRotatedEigenValues[i]; + unRotatedEigenValueTotal += this.orderedEigenValues[i]; + } + + + // Scale rotated loading factors and eigenvalues to the unrotated variance percentage for the sum of the extracted eigenvalues + double scale0 = Math.abs(unRotatedEigenValueTotal/usRotatedEigenValueTotal); + double scale1 = Math.sqrt(scale0); + for(int i=0; i<nRows; i++){ + this.rotatedEigenValues[i] = scale0*this.usRotatedEigenValues[i]; + this.rotatedProportionPercentage[i] = this.rotatedEigenValues[i]*100.0/this.eigenValueTotal; + for(int j=0; j<nColumns; j++){ + this.rotatedLoadingFactorsAsRows[i][j] = scale1*this.usRotatedLoadingFactorsAsRows[i][j]; + } + } + this.rotatedCumulativePercentage[0] = this.rotatedProportionPercentage[0]; + for(int i=1; i<nRows; i++)this.rotatedCumulativePercentage[i] = this.rotatedCumulativePercentage[i-1] + this.rotatedProportionPercentage[i]; + + this.rotationDone = true; + + } + + // Raw varimax rotation + // Static method - default tolerance and maximum iterations + public static double[][] rawVarimaxRotation(double[][] loadingFactorMatrix){ + double tolerance = 0.0001; + int nIterMax = 1000; + return PCA.rawVarimaxRotation(loadingFactorMatrix, tolerance, nIterMax); + } + + // Raw varimax rotation + // Static method - user supplied tolerance and maximum iterations + public static double[][] rawVarimaxRotation(double[][] loadingFactorMatrix, double tolerance, int nIterMax){ + int nRows = loadingFactorMatrix.length; + int nColumns = loadingFactorMatrix[0].length; + double[] communalityWeights = new double[nColumns]; + for(int i = 0; i<nColumns; i++){ + communalityWeights[i] = 0.0; + for(int j = 0; j<nRows; j++)communalityWeights[i] += loadingFactorMatrix[j][i]*loadingFactorMatrix[j][i]; + } + return PCA.normalVarimaxRotation(loadingFactorMatrix, communalityWeights, tolerance, nIterMax); + } + + // Normal varimax rotation - also used by raw varimax rotation with weights set to unity + // Static method - default tolerance and maximum iterations + public static double[][] normalVarimaxRotation(double[][] loadingFactorMatrix, double[] communalityWeights){ + double tolerance = 0.0001; + int nIterMax = 1000; + return normalVarimaxRotation(loadingFactorMatrix, communalityWeights, tolerance, nIterMax); + } + + // Normal varimax rotation - also used by raw varimax rotation with weights set to unity + // Static method - tolerance and maximum iterations provided by the user + public static double[][] normalVarimaxRotation(double[][] loadingFactorMatrix, double[] communalityWeights, double tolerance, int nIterMax){ + int nRows = loadingFactorMatrix.length; + int nColumns = loadingFactorMatrix[0].length; + for(int i=1; i<nRows; i++)if(loadingFactorMatrix[i].length!=nColumns)throw new IllegalArgumentException("All rows must be the same length"); + double[][] rotatedLoadingFactorsAsRows = new double[nRows][nColumns]; + + // Calculate weights and normalize the loading factors + for(int j = 0; j<nColumns; j++)communalityWeights[j] = Math.sqrt(communalityWeights[j]); + for(int i = 0; i<nRows; i++){ + for(int j = 0; j<nColumns; j++){ + loadingFactorMatrix[i][j] /= communalityWeights[j]; + rotatedLoadingFactorsAsRows[i][j] = loadingFactorMatrix[i][j]; + } + } + + // Loop through pairwise rotations until varimax function maximised + double va = PCA.varimaxCriterion(rotatedLoadingFactorsAsRows); + double vaLast = 0; + double angle = 0; + boolean test = true; + int nIter = 0; + while(test){ + for(int i=0; i<nRows-1; i++){ + for(int j=i+1; j<nRows; j++){ + angle = PCA.varimaxAngle(rotatedLoadingFactorsAsRows, i, j); + rotatedLoadingFactorsAsRows = PCA.singleRotation(rotatedLoadingFactorsAsRows, i, j, angle); + va = PCA.varimaxCriterion(rotatedLoadingFactorsAsRows); + } + } + if(Math.abs(va - vaLast)<tolerance){ + test=false; + } + else{ + vaLast = va; + nIter++; + if(nIter>nIterMax){ + test=false; + System.out.println("Method varimaxRotation: maximum iterations " + nIterMax + "exceeded"); + System.out.println("Current values returned"); + } + } + } + + // undo normalization of loading factors + for(int i=0; i<nRows; i++){ + for(int j=0; j<nColumns; j++){ + rotatedLoadingFactorsAsRows[i][j] *= communalityWeights[j]; + loadingFactorMatrix[i][j] *= communalityWeights[j]; + } + } + + return rotatedLoadingFactorsAsRows; + } + + // Transpose a matrix (as a possible aide to the use of the static methods) + public static double[][] transposeMatrix(double[][] matrix){ + int nRows = matrix.length; + int nColumns = matrix[0].length; + for(int i=1; i<nRows; i++)if(matrix[i].length!=nColumns)throw new IllegalArgumentException("All rows must be the same length"); + double[][] transpose = new double[nColumns][nRows]; + for(int i=0; i<nRows; i++){ + for(int j=0; j<nColumns; j++){ + transpose[j][i] = matrix[i][j]; + } + } + return transpose; + } + + // Varimax criterion calculation + public static double varimaxCriterion(double[][] loadingFactorMatrix){ + int nRows = loadingFactorMatrix.length; + int nColumns = loadingFactorMatrix[0].length; + double va1 = 0.0; + double va2 = 0.0; + double va3 = 0.0; + for(int j=0; j<nRows; j++){ + double sum1 = 0.0; + for(int k=0; k<nColumns; k++)sum1 += Math.pow(loadingFactorMatrix[j][k], 4); + va1 += sum1; + } + va1 *= nColumns; + for(int j=0; j<nRows; j++){ + double sum2 = 0.0; + for(int k=0; k<nColumns; k++)sum2 += Math.pow(loadingFactorMatrix[j][k], 2); + va2 += sum2*sum2; + } + va3 = va1 - va2; + return va3; + } + + // Varimax rotation angle calculation + // Kaiset maximization procedure + public static double varimaxAngle(double[][] loadingFactorMatrix, int k, int l){ + int nColumns = loadingFactorMatrix[0].length; + double uTerm = 0.0; + double vTerm = 0.0; + double bigA = 0.0; + double bigB = 0.0; + double bigC = 0.0; + double bigD = 0.0; + + for(int j=0; j<nColumns; j++){ + double lmjk = loadingFactorMatrix[k][j]; + double lmjl = loadingFactorMatrix[l][j]; + uTerm = lmjk*lmjk - lmjl*lmjl; + vTerm = 2.0*lmjk*lmjl; + bigA += uTerm; + bigB += vTerm; + bigC += uTerm*uTerm - vTerm*vTerm; + bigD += 2.0*uTerm*vTerm; + } + double bigE = bigD - 2.0*bigA*bigB/nColumns; + double bigF = bigC - (bigA*bigA - bigB*bigB)/nColumns; + double angle = 0.25*Math.atan2(bigE, bigF); + return angle; + } + + // Single rotation + public static double[][] singleRotation(double[][] loadingFactorMatrix, int k, int l, double angle){ + int nRows = loadingFactorMatrix.length; + int nColumns = loadingFactorMatrix[0].length; + double[][] rotatedMatrix = new double[nRows][nColumns]; + for(int i=0; i<nRows; i++){ + for(int j=0; j<nColumns; j++){ + rotatedMatrix[i][j] = loadingFactorMatrix[i][j]; + } + } + + double sinphi = Math.sin(angle); + double cosphi = Math.cos(angle); + for(int j=0; j<nColumns; j++){ + rotatedMatrix[k][j] = loadingFactorMatrix[k][j]*cosphi + loadingFactorMatrix[l][j]*sinphi; + rotatedMatrix[l][j] = -loadingFactorMatrix[k][j]*sinphi + loadingFactorMatrix[l][j]*cosphi; + } + return rotatedMatrix; + } + + + // RETURN DATA + + // Return eigenvalues as calculated + public double[] eigenValues(){ + if(!this.pcaDone)this.pca(); + return this.eigenValues; + } + + // Return eigenvalues ordered into a descending order + public double[] orderedEigenValues(){ + if(!this.pcaDone)this.pca(); + return this.orderedEigenValues; + } + + // Return indices of the eigenvalues before ordering into a descending order + public int[] eigenValueIndices(){ + if(!this.pcaDone)this.pca(); + return this.eigenValueIndices; + } + + // Return sum of the eigenvalues + public double eigenValueTotal(){ + if(!this.pcaDone)this.pca(); + return this.eigenValueTotal; + } + + + // Return eigenvalues ordered into a descending order and expressed as a percentage of total + public double[] proportionPercentage(){ + if(!this.pcaDone)this.pca(); + return this.proportionPercentage; + } + + // Return cumulative values of the eigenvalues ordered into a descending order and expressed as a percentage of total + public double[] cumulativePercentage(){ + if(!this.pcaDone)this.pca(); + return this.cumulativePercentage; + } + + // Return scaled rotated eigenvalues + public double[] rotatedEigenValues(){ + if(!this.rotationDone)throw new IllegalArgumentException("No rotation has been performed"); + return this.rotatedEigenValues; + } + + // Return scaled rotated eigenvalues as proportion of total variance + public double[] rotatedProportionPercentage(){ + if(!this.rotationDone)throw new IllegalArgumentException("No rotation has been performed"); + return this.rotatedProportionPercentage; + } + + // Return scaled rotated eigenvalues as cumulative percentages + public double[] rotatedCumulativePercentage(){ + if(!this.rotationDone)throw new IllegalArgumentException("No rotation has been performed"); + return this.rotatedCumulativePercentage; + } + + + + // Return eigenvectors as calculated + // Each column is the eigenvector for an eigenvalue + public double[][] eigenVectors(){ + if(!this.pcaDone)this.pca(); + return this.eigenVectorsAsColumns; + } + + // Return eigenvectors as calculated + // Each row is the eigenvector for an eigenvalue + public double[][] eigenVectorsAsRows(){ + if(!this.pcaDone)this.pca(); + return this.eigenVectorsAsRows; + } + + // Return eigenvector ordered to match the eigenvalues sorted into a descending order + // Each column is the eigenvector for an eigenvalue + public double[][] orderedEigenVectorsAsColumns(){ + if(!this.pcaDone)this.pca(); + return this.orderedEigenVectorsAsColumns; + } + + // Return eigenvector ordered to match the eigenvalues sorted into a descending order + // Each column is the eigenvector for an eigenvalue + public double[][] orderedEigenVectors(){ + if(!this.pcaDone)this.pca(); + return this.orderedEigenVectorsAsColumns; + } + + // Return eigenvector ordered to match the eigenvalues sorted into a descending order + // Each rowis the eigenvector for an eigenvalue + public double[][] orderedEigenVectorsAsRows(){ + if(!this.pcaDone)this.pca(); + return this.orderedEigenVectorsAsRows; + } + + // Return loading factors ordered to match the eigenvalues sorted into a descending order + // Each column is the loading factors for an eigenvalue + public double[][] loadingFactorsAsColumns(){ + if(!this.pcaDone)this.pca(); + return this.loadingFactorsAsColumns; + } + + // Return loading factors ordered to match the eigenvalues sorted into a descending order + // Each row is the loading factors for an eigenvalue + public double[][] loadingFactorsAsRows(){ + if(!this.pcaDone)this.pca(); + return this.loadingFactorsAsRows; + } + + // Return rotated loading factors as columns + public double[][] rotatedLoadingFactorsAsColumns(){ + if(!this.rotationDone)throw new IllegalArgumentException("No rotation has been performed"); + return this.rotatedLoadingFactorsAsColumns; + } + + // Return rotated loading factors as rows + public double[][] rotatedLoadingFactorsAsRows(){ + if(!this.rotationDone)throw new IllegalArgumentException("No rotation has been performed"); + return this.rotatedLoadingFactorsAsRows; + } + + // Return communalities + public double[] communalities(){ + if(!this.pcaDone)this.pca(); + return this.communalities; + } + + + // Return covariance matrix + public Matrix covarianceMatrix(){ + if(!this.pcaDone)this.pca(); + return this.covarianceMatrix; + } + + // Return correlation matrix + public Matrix correlationMatrix(){ + if(!this.pcaDone)this.pca(); + return this.correlationMatrix; + } + + // Return Monte Carlo means + public double[] monteCarloMeans(){ + if(!this.monteCarloDone)this.monteCarlo(); + return this.randomEigenValuesMeans; + } + + // Return Monte Carlo standard deviations + public double[] monteCarloStandardDeviations(){ + if(!this.monteCarloDone)this.monteCarlo(); + return this.randomEigenValuesSDs; + } + + // Return Monte Carlo percentiles + public double[] monteCarloPercentiles(){ + if(!this.monteCarloDone)this.monteCarlo(); + return this.randomEigenValuesPercentiles; + } + + // Return Monte Carlo eigenvalue matrix + public double[][] monteCarloEigenValues(){ + if(!this.monteCarloDone)this.monteCarlo(); + return this.randomEigenValues; + } + + // Return original data matrix + public Matrix originalData(){ + if(!this.pcaDone)this.pca(); + return this.data; + } + + // Return data minus row means divided by n-1 or n + public Matrix xMatrix(){ + if(!this.pcaDone)this.pca(); + double denom = this.nItems; + if(!super.nFactorOption)denom -= 1.0; + Matrix mat = dataMinusMeans.times(1.0/Math.sqrt(denom)); + return mat; + } + + // Return transpose of data minus row means divided by n-1 or n + public Matrix xMatrixTranspose(){ + if(!this.pcaDone)this.pca(); + double denom = this.nItems; + if(!super.nFactorOption)denom -= 1.0; + Matrix mat = dataMinusMeansTranspose.times(1.0/Math.sqrt(denom)); + return mat; + } + + // Return number of extracted components with eigenvalues greater than or equal to one + public int nEigenOneOrGreater(){ + if(!this.pcaDone)this.pca(); + return this.greaterThanOneLimit; + } + + // Return number of extracted components with eigenvalues greater than the corresponding Monte Carlo mean + public int nMeanCrossover(){ + if(!this.monteCarloDone)this.monteCarlo(); + return this.meanCrossover; + } + + // Return number of extracted components with eigenvalues greater than the corresponding Monte Carlo percentile + public int nPercentileCrossover(){ + if(!this.monteCarloDone)this.monteCarlo(); + return this.percentileCrossover; + } + + // OUTPUT THE ANALYSIS + + // Full analysis without output of input data + // no input file name entered via method argument list + public void analysis(){ + + + this.outputFilename = "PCAOutput"; + if(this.fileOption==1){ + this.outputFilename += ".txt"; + } + else{ + this.outputFilename += ".xls"; + } + String message1 = "Output file name for the analysis details:"; + String message2 = "\nEnter the required name (as a single word) and click OK "; + String message3 = "\nor simply click OK for default value"; + String message = message1 + message2 + message3; + String defaultName = this.outputFilename; + this.outputFilename = Db.readLine(message, defaultName); + this.analysis(this.outputFilename); + } + + // Full analysis without output of input data + // input file name via method argument list + public void analysis(String filename){ + + // Scree Plot + this.screePlot(); + + // Open output file + this.outputFilename = filename; + String outputFilenameWithoutExtension = null; + String extension = null; + int pos = filename.indexOf('.'); + if(pos==-1){ + outputFilenameWithoutExtension = filename; + if(this.fileOption==1){ + this.outputFilename += ".txt"; + } + else{ + this.outputFilename += ".xls"; + } + } + else{ + extension = (filename.substring(pos)).trim(); + + outputFilenameWithoutExtension = (filename.substring(0, pos)).trim(); + if(extension.equalsIgnoreCase(".xls")){ + if(this.fileOption==1){ + if(this.fileOptionSet){ + String message1 = "Your entered output file type is .xls"; + String message2 = "\nbut you have chosen a .txt output"; + String message = message1 + message2; + String headerComment = "Your output file name extension"; + String[] comments = {message, "replace it with .txt [text file]"}; + String[] boxTitles = {"Retain", ".txt"}; + int defaultBox = 1; + int opt = Db.optionBox(headerComment, comments, boxTitles, defaultBox); + if(opt==2)this.outputFilename = outputFilenameWithoutExtension + ".txt"; + } + else{ + this.fileOption=2; + } + } + } + + if(extension.equalsIgnoreCase(".txt")){ + if(this.fileOption==2){ + if(this.fileOptionSet){ + String message1 = "Your entered output file type is .txt"; + String message2 = "\nbut you have chosen a .xls output"; + String message = message1 + message2; + String headerComment = "Your output file name extension"; + String[] comments = {message, "replace it with .xls [Excel file]"}; + String[] boxTitles = {"Retain", ".xls"}; + int defaultBox = 1; + int opt = Db.optionBox(headerComment, comments, boxTitles, defaultBox); + if(opt==2)this.outputFilename = outputFilenameWithoutExtension + ".xls"; + } + else{ + this.fileOption=1; + } + } + } + + if(!extension.equalsIgnoreCase(".txt") && !extension.equalsIgnoreCase(".xls")){ + String message1 = "Your extension is " + extension; + String message2 = "\n Do you wish to retain it:"; + String message = message1 + message2; + String headerComment = "Your output file name extension"; + String[] comments = {message, "replace it with .txt [text file]", "replace it with .xls [MS Excel file]"}; + String[] boxTitles = {"Retain", ".txt", ".xls"}; + int defaultBox = 1; + int opt = Db.optionBox(headerComment, comments, boxTitles, defaultBox); + switch(opt){ + case 1: this.fileOption=1; + break; + case 2: this.outputFilename = outputFilenameWithoutExtension + ".txt"; + this.fileOption=1; + break; + case 3: this.outputFilename = outputFilenameWithoutExtension + ".xls"; + this.fileOption=2; + break; + } + } + } + + if(this.fileOption==1){ + this.analysisText(); + } + else{ + this.analysisExcel(); + } + + System.out.println("The analysis has been written to the file " + this.outputFilename); + } + + // Output analysis to a text (.txt) file + private void analysisText(){ + + FileOutput fout = null; + if(this.fileNumberingSet){ + fout = new FileOutput(this.outputFilename, 'n'); + } + else{ + fout = new FileOutput(this.outputFilename); + } + + // perform PCA if not already performed + if(!pcaDone)this.pca(); + if(!this.monteCarloDone)this.monteCarlo(); + + // output title + fout.println("PRINCIPAL COMPONENT ANALYSIS"); + fout.println("Program: PCA - Analysis Output"); + for(int i=0; i<this.titleLines; i++)fout.println(title[i]); + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + fout.println("Program executed at " + tim + " on " + day); + fout.println(); + if(this.covRhoOption){ + fout.println("Covariance matrix used"); + } + else{ + fout.println("Correlation matrix used"); + } + fout.println(); + + // output eigenvalue table + // field width + int field1 = 10; + int field2 = 12; + int field3 = 2; + + fout.println("ALL EIGENVALUES"); + + fout.print("Component ", field1); + fout.print("Unordered ", field1); + fout.print("Eigenvalue ", field2); + fout.print("Proportion ", field2); + fout.print("Cumulative ", field2); + fout.println("Difference "); + + fout.print(" ", field1); + fout.print("index", field1); + fout.print(" ", field2); + fout.print("as % ", field2); + fout.print("percentage ", field2); + fout.println(" "); + + + + for(int i=0; i<this.nItems; i++){ + fout.print(i+1, field1); + fout.print((this.eigenValueIndices[i]+1), field1); + fout.print(Fmath.truncate(this.orderedEigenValues[i], this.trunc), field2); + fout.print(Fmath.truncate(this.proportionPercentage[i], this.trunc), field2); + fout.print(Fmath.truncate(this.cumulativePercentage[i], this.trunc), field2); + if(i<this.nItems-1){ + fout.print(Fmath.truncate((this.orderedEigenValues[i] - this.orderedEigenValues[i+1]), this.trunc), field2); + } + else{ + fout.print(" ", field2); + } + fout.print(" ", field3); + + fout.println(); + } + fout.println(); + + + // Extracted components + int nMax = this.greaterThanOneLimit; + if(nMax<this.meanCrossover)nMax=this.meanCrossover; + if(nMax<this.percentileCrossover)nMax=this.percentileCrossover; + fout.println("EXTRACTED EIGENVALUES"); + fout.print(" ", field1); + fout.print("Greater than unity", 3*field2 + field3); + fout.print("Greater than Monte Carlo Mean ", 3*field2 + field3); + fout.println("Greater than Monte Carlo Percentile"); + + fout.print("Component ", field1); + fout.print("Eigenvalue ", field2); + fout.print("Proportion ", field2); + fout.print("Cumulative ", field2); + fout.print(" ", field3); + + fout.print("Eigenvalue ", field2); + fout.print("Proportion ", field2); + fout.print("Cumulative ", field2); + fout.print(" ", field3); + + fout.print("Eigenvalue ", field2); + fout.print("Proportion ", field2); + fout.print("Cumulative ", field2); + fout.println(" "); + + fout.print(" ", field1); + fout.print(" ", field2); + fout.print("as % ", field2); + fout.print("percentage ", field2); + fout.print(" ", field3); + + fout.print(" ", field2); + fout.print("as % ", field2); + fout.print("percentage ", field2); + fout.print(" ", field3); + + fout.print(" ", field2); + fout.print("as % ", field2); + fout.print("percentage ", field2); + fout.println(" "); + + int ii=0; + while(ii<nMax){ + fout.print(ii+1, field1); + + if(ii<this.greaterThanOneLimit){ + fout.print(Fmath.truncate(this.orderedEigenValues[ii], this.trunc), field2); + fout.print(Fmath.truncate(this.proportionPercentage[ii], this.trunc), field2); + fout.print(Fmath.truncate(this.cumulativePercentage[ii], this.trunc), (field2+field3)); + } + + if(ii<this.meanCrossover){ + fout.print(Fmath.truncate(this.orderedEigenValues[ii], this.trunc), field2); + fout.print(Fmath.truncate(this.proportionPercentage[ii], this.trunc), field2); + fout.print(Fmath.truncate(this.cumulativePercentage[ii], this.trunc), (field2+field3)); + } + + if(ii<this.percentileCrossover){ + fout.print(Fmath.truncate(this.orderedEigenValues[ii], this.trunc), field2); + fout.print(Fmath.truncate(this.proportionPercentage[ii], this.trunc), field2); + fout.print(Fmath.truncate(this.cumulativePercentage[ii], this.trunc)); + } + fout.println(); + ii++; + } + fout.println(); + + + fout.println("PARALLEL ANALYSIS"); + fout.println("Number of simulations = " + this.nMonteCarlo); + if(this.gaussianDeviates){ + fout.println("Gaussian random deviates used"); + } + else{ + fout.println("Uniform random deviates used"); + } + fout.println("Percentile value used = " + this.percentile + " %"); + + fout.println(); + fout.print("Component ", field1); + fout.print("Data ", field2); + fout.print("Proportion ", field2); + fout.print("Cumulative ", field2); + fout.print(" ", field3); + fout.print("Data ", field2); + fout.print("Monte Carlo ", field2); + fout.print("Monte Carlo ", field2); + fout.println("Monte Carlo "); + + fout.print(" ", field1); + fout.print("Eigenvalue ", field2); + fout.print("as % ", field2); + fout.print("percentage ", field2); + fout.print(" ", field3); + fout.print("Eigenvalue ", field2); + fout.print("Eigenvalue ", field2); + fout.print("Eigenvalue ", field2); + fout.println("Eigenvalue "); + + fout.print(" ", field1); + fout.print(" ", field2); + fout.print(" ", field2); + fout.print(" ", field2); + fout.print(" ", field3); + fout.print(" ", field2); + fout.print("Percentile ", field2); + fout.print("Mean ", field2); + fout.println("Standard Deviation "); + + for(int i=0; i<this.nItems; i++){ + fout.print(i+1, field1); + fout.print(Fmath.truncate(this.orderedEigenValues[i], this.trunc), field2); + fout.print(Fmath.truncate(this.proportionPercentage[i], this.trunc), field2); + fout.print(Fmath.truncate(this.cumulativePercentage[i], this.trunc), field2); + fout.print(" ", field3); + fout.print(Fmath.truncate(this.orderedEigenValues[i], this.trunc), field2); + fout.print(Fmath.truncate(this.randomEigenValuesPercentiles[i], this.trunc), field2); + fout.print(Fmath.truncate(this.randomEigenValuesMeans[i], this.trunc), field2); + fout.println(Fmath.truncate(this.randomEigenValuesSDs[i], this.trunc)); + } + fout.println(); + + // Correlation Matrix + fout.println("CORRELATION MATRIX"); + fout.println("Original component indices in parenthesis"); + fout.println(); + fout.print(" ", field1); + fout.print("component", field1); + for(int i=0; i<this.nItems; i++)fout.print((this.eigenValueIndices[i]+1) + " (" + (i+1) + ")", field2); + fout.println(); + fout.println("component"); + for(int i=0; i<this.nItems; i++){ + fout.print((this.eigenValueIndices[i]+1) + " (" + (i+1) + ")", 2*field1); + for(int j=0; j<this.nItems; j++)fout.print(Fmath.truncate(this.correlationMatrix.getElement(j,i), this.trunc), field2); + fout.println(); + } + fout.println(); + + // Covariance Matrix + fout.println("COVARIANCE MATRIX"); + fout.println("Original component indices in parenthesis"); + fout.println(); + fout.print(" ", field1); + fout.print("component", field1); + for(int i=0; i<this.nItems; i++)fout.print((this.eigenValueIndices[i]+1) + " (" + (i+1) + ")", field2); + fout.println(); + fout.println("component"); + for(int i=0; i<this.nItems; i++){ + fout.print((this.eigenValueIndices[i]+1) + " (" + (i+1) + ")", 2*field1); + for(int j=0; j<this.nItems; j++)fout.print(Fmath.truncate(this.covarianceMatrix.getElement(j,i), this.trunc), field2); + fout.println(); + } + + fout.println(); + + // Eigenvectors + fout.println("EIGENVECTORS"); + fout.println("Original component indices in parenthesis"); + fout.println("Vector corresponding to an ordered eigenvalues in each row"); + fout.println(); + fout.print(" ", field1); + fout.print("component", field1); + for(int i=0; i<this.nItems; i++)fout.print((this.eigenValueIndices[i]+1) + " (" + (i+1) + ")", field2); + fout.println(); + fout.println("component"); + for(int i=0; i<this.nItems; i++){ + fout.print((i+1) + " (" + (this.eigenValueIndices[i]+1) + ")", 2*field1); + for(int j=0; j<this.nItems; j++)fout.print(Fmath.truncate(this.orderedEigenVectorsAsRows[i][j], this.trunc), field2); + fout.println(); + } + fout.println(); + + // Loading factors + fout.println("LOADING FACTORS"); + fout.println("Original indices in parenthesis"); + fout.println("Loading factors corresponding to an ordered eigenvalues in each row"); + fout.println(); + fout.print(" ", field1); + fout.print("component", field1); + for(int i=0; i<this.nItems; i++)fout.print((this.eigenValueIndices[i]+1) + " (" + (i+1) + ")", field2); + fout.print(" ", field1); + fout.print("Eigenvalue", field2); + fout.print("Proportion", field2); + fout.println("Cumulative %"); + fout.println("factor"); + for(int i=0; i<this.nItems; i++){ + fout.print((i+1) + " (" + (this.eigenValueIndices[i]+1) + ")", 2*field1); + for(int j=0; j<this.nItems; j++)fout.print(Fmath.truncate(this.loadingFactorsAsRows[i][j], this.trunc), field2); + fout.print(" ", field1); + fout.print(Fmath.truncate(this.orderedEigenValues[i], this.trunc), field2); + fout.print(Fmath.truncate(proportionPercentage[i], this.trunc), field2); + fout.println(Fmath.truncate(cumulativePercentage[i], this.trunc)); + } + fout.println(); + + // Rotated loading factors + fout.println("ROTATED LOADING FACTORS"); + if(this.varimaxOption){ + fout.println("NORMAL VARIMAX"); + } + else{ + fout.println("RAW VARIMAX"); + } + + String message = "The ordered eigenvalues with Monte Carlo means and percentiles in parenthesis"; + message += "\n (Total number of eigenvalues = " + this.nItems + ")"; + int nDisplay = this.nItems; + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + int screenHeight = screenSize.height; + int nDisplayLimit = 20*screenHeight/800; + if(nDisplay>nDisplay)nDisplay = nDisplayLimit; + for(int i=0; i<nDisplay; i++){ + message += "\n " + Fmath.truncate(this.orderedEigenValues[i], 4) + " (" + Fmath.truncate(this.randomEigenValuesMeans[i], 4) + " " + Fmath.truncate(this.randomEigenValuesPercentiles[i], 4) + ")"; + } + if(nDisplay<this.nItems)message += "\n . . . "; + message += "\nEnter number of eigenvalues to be extracted"; + int nExtracted = this.greaterThanOneLimit; + nExtracted = Db.readInt(message, nExtracted); + this.varimaxRotation(nExtracted); + + fout.println("Varimax rotation for " + nExtracted + " extracted factors"); + fout.println("Rotated loading factors and eigenvalues scaled to ensure total 'rotated variance' matches unrotated variance for the extracted factors"); + fout.println("Original indices in parenthesis"); + fout.println(); + fout.print(" ", field1); + fout.print("component", field1); + for(int i=0; i<this.nItems; i++)fout.print((this.eigenValueIndices[i]+1) + " (" + (i+1) + ")", field2); + fout.print(" ", field1); + fout.print("Eigenvalue", field2); + fout.print("Proportion", field2); + fout.println("Cumulative %"); + fout.println("factor"); + + for(int i=0; i<nExtracted; i++){ + fout.print((i+1) + " (" + (this.eigenValueIndices[i]+1) + ")", 2*field1); + for(int j=0; j<this.nItems; j++)fout.print(Fmath.truncate(this.rotatedLoadingFactorsAsRows[i][j], this.trunc), field2); + fout.print(" ", field1); + fout.print(Fmath.truncate(rotatedEigenValues[i], this.trunc), field2); + fout.print(Fmath.truncate(rotatedProportionPercentage[i], this.trunc), field2); + fout.println(Fmath.truncate(rotatedCumulativePercentage[i], this.trunc)); + } + fout.println(); + + + fout.close(); + } + + // Output to an Excel readable file + private void analysisExcel(){ + + FileOutput fout = null; + if(this.fileNumberingSet){ + fout = new FileOutput(this.outputFilename, 'n'); + } + else{ + fout = new FileOutput(this.outputFilename); + } + + // perform PCA if not already performed + if(!pcaDone)this.pca(); + if(!this.monteCarloDone)this.monteCarlo(); + + // output title + fout.println("PRINCIPAL COMPONENT ANALYSIS"); + fout.println("Program: PCA - Analysis Output"); + for(int i=0; i<this.titleLines; i++)fout.println(title[i]); + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + fout.println("Program executed at " + tim + " on " + day); + fout.println(); + if(this.covRhoOption){ + fout.println("Covariance matrix used"); + } + else{ + fout.println("Correlation matrix used"); + } + fout.println(); + + // output eigenvalue table + fout.println("ALL EIGENVALUES"); + + fout.printtab("Component "); + fout.printtab("Unordered "); + fout.printtab("Eigenvalue "); + fout.printtab("Proportion "); + fout.printtab("Cumulative "); + fout.println("Difference "); + + fout.printtab(" "); + fout.printtab("index"); + fout.printtab(" "); + fout.printtab("as % "); + fout.printtab("percentage "); + fout.println(" "); + + + + for(int i=0; i<this.nItems; i++){ + fout.printtab(i+1); + fout.printtab((this.eigenValueIndices[i]+1)); + fout.printtab(Fmath.truncate(this.orderedEigenValues[i], this.trunc)); + fout.printtab(Fmath.truncate(this.proportionPercentage[i], this.trunc)); + fout.printtab(Fmath.truncate(this.cumulativePercentage[i], this.trunc)); + if(i<this.nItems-1){ + fout.printtab(Fmath.truncate((this.orderedEigenValues[i] - this.orderedEigenValues[i+1]), this.trunc)); + } + else{ + fout.printtab(" "); + } + fout.printtab(" "); + + fout.println(); + } + fout.println(); + + + // Extracted components + int nMax = this.greaterThanOneLimit; + if(nMax<this.meanCrossover)nMax=this.meanCrossover; + if(nMax<this.percentileCrossover)nMax=this.percentileCrossover; + fout.println("EXTRACTED EIGENVALUES"); + fout.printtab(" "); + fout.printtab("Greater than unity"); + fout.printtab(" ");fout.printtab(" ");fout.printtab(" "); + fout.printtab("Greater than Monte Carlo Mean "); + fout.printtab(" ");fout.printtab(" ");fout.printtab(" "); + fout.println("Greater than Monte Carlo Percentile"); + + fout.printtab("Component "); + fout.printtab("Eigenvalue "); + fout.printtab("Proportion "); + fout.printtab("Cumulative "); + fout.printtab(" "); + + fout.printtab("Eigenvalue "); + fout.printtab("Proportion "); + fout.printtab("Cumulative "); + fout.printtab(" "); + + fout.printtab("Eigenvalue "); + fout.printtab("Proportion "); + fout.printtab("Cumulative "); + fout.println(" "); + + fout.printtab(" "); + fout.printtab(" "); + fout.printtab("as % "); + fout.printtab("percentage "); + fout.printtab(" "); + + fout.printtab(" "); + fout.printtab("as % "); + fout.printtab("percentage "); + fout.printtab(" "); + + fout.printtab(" "); + fout.printtab("as % "); + fout.printtab("percentage "); + fout.println(" "); + + int ii=0; + while(ii<nMax){ + fout.printtab(ii+1); + + if(ii<this.greaterThanOneLimit){ + fout.printtab(Fmath.truncate(this.orderedEigenValues[ii], this.trunc)); + fout.printtab(Fmath.truncate(this.proportionPercentage[ii], this.trunc)); + fout.printtab(Fmath.truncate(this.cumulativePercentage[ii], this.trunc)); + fout.printtab(" "); + } + + if(ii<this.meanCrossover){ + fout.printtab(Fmath.truncate(this.orderedEigenValues[ii], this.trunc)); + fout.printtab(Fmath.truncate(this.proportionPercentage[ii], this.trunc)); + fout.printtab(Fmath.truncate(this.cumulativePercentage[ii], this.trunc)); + fout.printtab(" "); + } + + if(ii<this.percentileCrossover){ + fout.printtab(Fmath.truncate(this.orderedEigenValues[ii], this.trunc)); + fout.printtab(Fmath.truncate(this.proportionPercentage[ii], this.trunc)); + fout.printtab(Fmath.truncate(this.cumulativePercentage[ii], this.trunc)); + } + fout.println(); + ii++; + } + fout.println(); + + + fout.println("PARALLEL ANALYSIS"); + fout.println("Number of simulations = " + this.nMonteCarlo); + if(this.gaussianDeviates){ + fout.println("Gaussian random deviates used"); + } + else{ + fout.println("Uniform random deviates used"); + } + fout.println("Percentile value used = " + this.percentile + " %"); + + fout.println(); + fout.printtab("Component "); + fout.printtab("Data "); + fout.printtab("Proportion "); + fout.printtab("Cumulative "); + fout.printtab(" "); + fout.printtab("Data "); + fout.printtab("Monte Carlo "); + fout.printtab("Monte Carlo "); + fout.println("Monte Carlo "); + + fout.printtab(" "); + fout.printtab("Eigenvalue "); + fout.printtab("as % "); + fout.printtab("percentage "); + fout.printtab(" "); + fout.printtab("Eigenvalue "); + fout.printtab("Eigenvalue "); + fout.printtab("Eigenvalue "); + fout.println("Eigenvalue "); + + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab("Percentile "); + fout.printtab("Mean "); + fout.println("Standard Deviation "); + + for(int i=0; i<this.nItems; i++){ + fout.printtab(i+1); + fout.printtab(Fmath.truncate(this.orderedEigenValues[i], this.trunc)); + fout.printtab(Fmath.truncate(this.proportionPercentage[i], this.trunc)); + fout.printtab(Fmath.truncate(this.cumulativePercentage[i], this.trunc)); + fout.printtab(" "); + fout.printtab(Fmath.truncate(this.orderedEigenValues[i], this.trunc)); + fout.printtab(Fmath.truncate(this.randomEigenValuesPercentiles[i], this.trunc)); + fout.printtab(Fmath.truncate(this.randomEigenValuesMeans[i], this.trunc)); + fout.println(Fmath.truncate(this.randomEigenValuesSDs[i], this.trunc)); + } + fout.println(); + + // Correlation Matrix + fout.println("CORRELATION MATRIX"); + fout.println("Original component indices in parenthesis"); + fout.println(); + fout.printtab(" "); + fout.printtab("component"); + for(int i=0; i<this.nItems; i++)fout.printtab((this.eigenValueIndices[i]+1) + " (" + (i+1) + ")"); + fout.println(); + fout.println("component"); + for(int i=0; i<this.nItems; i++){ + fout.printtab((this.eigenValueIndices[i]+1) + " (" + (i+1) + ")"); + fout.printtab(" "); + for(int j=0; j<this.nItems; j++)fout.printtab(Fmath.truncate(this.correlationMatrix.getElement(j,i), this.trunc)); + fout.println(); + } + fout.println(); + + // Covariance Matrix + fout.println("COVARIANCE MATRIX"); + fout.println("Original component indices in parenthesis"); + fout.println(); + fout.printtab(" "); + fout.printtab("component"); + for(int i=0; i<this.nItems; i++)fout.printtab((this.eigenValueIndices[i]+1) + " (" + (i+1) + ")"); + fout.println(); + fout.println("component"); + for(int i=0; i<this.nItems; i++){ + fout.printtab((this.eigenValueIndices[i]+1) + " (" + (i+1) + ")"); + fout.printtab(" "); + for(int j=0; j<this.nItems; j++)fout.printtab(Fmath.truncate(this.covarianceMatrix.getElement(j,i), this.trunc)); + fout.println(); + } + fout.println(); + + // Eigenvectors + fout.println("EIGENVECTORS"); + fout.println("Original component indices in parenthesis"); + fout.println("Vector corresponding to an ordered eigenvalues in each row"); + fout.println(); + fout.printtab(" "); + fout.printtab("component"); + for(int i=0; i<this.nItems; i++)fout.printtab((this.eigenValueIndices[i]+1) + " (" + (i+1) + ")"); + fout.println(); + fout.println("component"); + + for(int i=0; i<this.nItems; i++){ + fout.printtab((i+1) + " (" + (this.eigenValueIndices[i]+1) + ")"); + fout.printtab(" "); + for(int j=0; j<this.nItems; j++)fout.printtab(Fmath.truncate(this.orderedEigenVectorsAsRows[i][j], this.trunc)); + fout.println(); + } + fout.println(); + + // Loading factors + fout.println("LOADING FACTORS"); + fout.println("Original indices in parenthesis"); + fout.println("Loading factors corresponding to an ordered eigenvalues in each row"); + fout.println(); + fout.printtab(" "); + fout.printtab("component"); + for(int i=0; i<this.nItems; i++)fout.printtab((this.eigenValueIndices[i]+1) + " (" + (i+1) + ")"); + fout.printtab(" "); + fout.printtab("Eigenvalue"); + fout.printtab("% Proportion"); + fout.println("Cumulative %"); + fout.println("factor"); + for(int i=0; i<this.nItems; i++){ + fout.printtab((i+1) + " (" + (this.eigenValueIndices[i]+1) + ")"); + fout.printtab(" "); + for(int j=0; j<this.nItems; j++)fout.printtab(Fmath.truncate(this.loadingFactorsAsRows[i][j], this.trunc)); + fout.printtab(" "); + fout.printtab(Fmath.truncate(this.orderedEigenValues[i], this.trunc)); + fout.printtab(Fmath.truncate(proportionPercentage[i], this.trunc)); + fout.println(Fmath.truncate(cumulativePercentage[i], this.trunc)); + } + fout.println(); + + // Rotated loading factors + fout.println("ROTATED LOADING FACTORS"); + if(this.varimaxOption){ + fout.println("NORMAL VARIMAX"); + } + else{ + fout.println("RAW VARIMAX"); + } + + String message = "The ordered eigenvalues with Monte Carlo means and percentiles in parenthesis"; + message += "\n (Total number of eigenvalues = " + this.nItems + ")"; + int nDisplay = this.nItems; + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + int screenHeight = screenSize.height; + int nDisplayLimit = 20*screenHeight/800; + if(nDisplay>nDisplay)nDisplay = nDisplayLimit; + for(int i=0; i<nDisplay; i++){ + message += "\n " + Fmath.truncate(this.orderedEigenValues[i], 4) + " (" + Fmath.truncate(this.randomEigenValuesMeans[i], 4) + " " + Fmath.truncate(this.randomEigenValuesPercentiles[i], 4) + ")"; + } + if(nDisplay<this.nItems)message += "\n . . . "; + message += "\nEnter number of eigenvalues to be extracted"; + int nExtracted = this.greaterThanOneLimit; + nExtracted = Db.readInt(message, nExtracted); + this.varimaxRotation(nExtracted); + + fout.println("Varimax rotation for " + nExtracted + " extracted factors"); + fout.println("Rotated loading factors and eigenvalues scaled to ensure total 'rotated variance' matches unrotated variance for the extracted factors"); + fout.println("Original indices in parenthesis"); + fout.println(); + fout.printtab(" "); + fout.printtab("component"); + for(int i=0; i<this.nItems; i++)fout.printtab((this.eigenValueIndices[i]+1) + " (" + (i+1) + ")"); + fout.printtab(" "); + fout.printtab("Eigenvalue"); + fout.printtab("% Proportion"); + fout.println("Cumulative %"); + fout.println("factor"); + for(int i=0; i<nExtracted; i++){ + fout.printtab((i+1) + " (" + (this.eigenValueIndices[i]+1) + ")"); + fout.printtab(" "); + for(int j=0; j<this.nItems; j++)fout.printtab(Fmath.truncate(this.rotatedLoadingFactorsAsRows[i][j], this.trunc)); + fout.printtab(" "); + fout.printtab(Fmath.truncate(rotatedEigenValues[i], this.trunc)); + fout.printtab(Fmath.truncate(rotatedProportionPercentage[i], this.trunc)); + fout.println(Fmath.truncate(rotatedCumulativePercentage[i], this.trunc)); + } + fout.println(); + + fout.close(); + } +} + diff --git a/src/main/java/flanagan/analysis/ProbabilityPlot.java b/src/main/java/flanagan/analysis/ProbabilityPlot.java new file mode 100755 index 0000000000000000000000000000000000000000..11544dbc44927c74b46e792c628745e73c67868a --- /dev/null +++ b/src/main/java/flanagan/analysis/ProbabilityPlot.java @@ -0,0 +1,3114 @@ +/* +* Class ProbabilityPlot +* +* USAGE: Probability Plots +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 29-30 September 2008, 1-5 October 2008, 13-24 October 2009 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ProbabilityPlot.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.analysis; + +import java.util.*; +import java.math.*; + +import flanagan.math.*; +import flanagan.plot.PlotGraph; +import flanagan.interpolation.CubicSpline; +import flanagan.io.PrintToScreen; + +public class ProbabilityPlot{ + + // INSTANCE VARIABLES + private double[] array = null; // array of data + private Stat arrayAsStat = null; // array of data as Stat + private double[] sortedData = null; // data sorted into ascending order + + private double[] weights = null; // weights + private boolean weighted = false; // = true if weighted regression to be performed + + private double mean = Double.NaN; // array mean + private double standardDeviation = Double.NaN; // array standard deviation + private double minimum = Double.NaN; // array minimum + private double maximum = Double.NaN; // array maximum + private double range = Double.NaN; // array range + private double halfWidth = Double.NaN; // rough estimate of peak width at half peak height + private double peakPoint = Double.NaN; // rough estimate of peak position + + private int numberOfDataPoints = 0; // number of data points + + private double dataOffset = 0.0; // data offset if data shifted + private boolean dataShifted = false; // = true if data offset + + private double[] initialEstimates = null; // initial estimates used in last call to a probability plot method + + private int lastMethod = 0; // Last probability plot method called + // 0 Gaussian + // 1 Weibull (three parameter) + // 2 Exponential + // 3 Rayleigh + // 4 Pareto + // 5 Gumbel (minimum order statistic) + // 6 Gumbel (maximum order statistic) + // 7 Frechet + // 8 Logistic + // 9 Lorentzian // TO BE ADDED + // 10 Log-Normal (three parameter) // TO BE ADDED + // 11 Log-Normal (two parameter // TO BE ADDED + // 12 Weibull (two parameter) + // 13 Weibull (standard) + // 14 Standard Gaussian + // 15 F-distribution + + + private int gaussianNumberOfParameters = 2; // number of Gaussian parameters + private double[] gaussianOrderMedians = null; // Gaussian order statistic medians + private double[] gaussianParam = null; // Gaussian parameters obtained by the minimization procedure + private double[] gaussianParamErrors = null; // estimates of the errors of the Gaussian parameters obtained by the minimization procedure + private double gaussianSumOfSquares = Double.NaN; // sum of squares at Gaussian minimum + private double gaussianUnweightedSumOfSquares = Double.NaN; // unweighted sum of squares at Gaussian minimum + private double[] gaussianLine = null; // Gaussian probability plot gradient and intercept + private double[] gaussianLineErrors = null; // estimated errors of the Gaussian probability plot gradient and intercept + private double gaussianCorrCoeff = Double.NaN; // Gaussian correlation coefficient of the probability plot + private boolean gaussianDone = false; // = true after Gaussian probability plot drawn + + private int gaussianStandardNumberOfParameters = 0; // number of Standard Gauss parameters + private double[] gaussianStandardOrderMedians = null; // Standard Gauss order statistic medians + private double gaussianStandardSumOfSquares = Double.NaN; // sum of squares at Standard Gauss minimum + private double[] gaussianStandardLine = null; // Standard Gauss probability plot gradient and intercept + private double[] gaussianStandardLineErrors = null; // estimated errors of the Standard Gauss probability plot gradient and intercept + private double gaussianStandardCorrCoeff = Double.NaN; // Standard Gauss correlation coefficient of the probability plot + private boolean gaussianStandardDone = false; // = true after Standard Gauss probability plot drawn + + private int exponentialNumberOfParameters = 2; // number of Exponential parameters + private double[] exponentialOrderMedians = null; // Exponential order statistic medians + private double[] exponentialParam = null; // Exponential parameters obtained by the minimization procedure + private double[] exponentialParamErrors = null; // estimates of the errors of the Exponential parameters obtained by the minimization procedure + private double exponentialSumOfSquares = Double.NaN; // sum of squares at Exponential minimum + private double[] exponentialLine = null; // Exponential probability plot gradient and intercept + private double[] exponentialLineErrors = null; // estimated errors of the Exponential probability plot gradient and intercept + private double exponentialCorrCoeff = Double.NaN; // Exponential correlation coefficient of the probability plot + private boolean exponentialDone = false; // = true after Exponential probability plot drawn + + private int fDistributionNumberOfParameters = 0; // number of F-distribution parameters + private double[] fDistributionOrderMedians = null; // F-distribution order statistic medians + private double fDistributionSumOfSquares = Double.NaN; // sum of squares at F-distribution minimum + private double[] fDistributionLine = null; // F-distribution probability plot gradient and intercept + private double[] fDistributionLineErrors = null; // estimated errors of the F-distribution probability plot gradient and intercept + private double fDistributionCorrCoeff = Double.NaN; // F-distribution correlation coefficient of the probability plot + private boolean fDistributionDone = false; // = true after F-distribution probability plot drawn + + private int frechetNumberOfParameters = 3; // number of Frechet parameters + private double[] frechetOrderMedians = null; // Frechet order statistic medians + private double[] frechetParam = null; // Frechet parameters obtained by the minimization procedure + private double[] frechetParamErrors = null; // estimates of the errors of the Frechet parameters obtained by the minimization procedure + private double frechetSumOfSquares = Double.NaN; // sum of squares at Frechet minimum + private double[] frechetLine = null; // Frechet probability plot gradient and intercept + private double[] frechetLineErrors = null; // estimated errors of the Frechet probability plot gradient and intercept + private double frechetCorrCoeff = Double.NaN; // Frechet correlation coefficient of the probability plot + private boolean frechetDone = false; // = true after Frechet probability plot drawn + + private int gumbelMinNumberOfParameters = 3; // number of Gumbel (minimum order statistic) parameters + private double[] gumbelMinOrderMedians = null; // Gumbel (minimum order statistic) order statistic medians + private double[] gumbelMinParam = null; // Gumbel (minimum order statistic) parameters obtained by the minimization procedure + private double[] gumbelMinParamErrors = null; // estimates of the errors of the Gumbel (minimum order statistic) parameters obtained by the minimization procedure + private double gumbelMinSumOfSquares = Double.NaN; // sum of squares at Gumbel (minimum order statistic) minimum + private double[] gumbelMinLine = null; // Gumbel (minimum order statistic) probability plot gradient and intercept + private double[] gumbelMinLineErrors = null; // estimated errors of the Gumbel (minimum order statistic) probability plot gradient and intercept + private double gumbelMinCorrCoeff = Double.NaN; // Gumbel (minimum order statistic) correlation coefficient of the probability plot + private boolean gumbelMinDone = false; // = true after Gumbel (minimum order statistic) probability plot drawn + + private int gumbelMaxNumberOfParameters = 3; // number of Gumbel (maximum order statistic) parameters + private double[] gumbelMaxOrderMedians = null; // Gumbel (maximum order statistic) order statistic medians + private double[] gumbelMaxParam = null; // Gumbel (maximum order statistic) parameters obtained by the maximization procedure + private double[] gumbelMaxParamErrors = null; // estimates of the errors of the Gumbel (maximum order statistic) parameters obtained by the maximization procedure + private double gumbelMaxSumOfSquares = Double.NaN; // sum of squares at Gumbel (maximum order statistic) maximum + private double[] gumbelMaxLine = null; // Gumbel (maximum order statistic) probability plot gradient and intercept + private double[] gumbelMaxLineErrors = null; // estimated errors of the Gumbel (maximum order statistic) probability plot gradient and intercept + private double gumbelMaxCorrCoeff = Double.NaN; // Gumbel (maximum order statistic) correlation coefficient of the probability plot + private boolean gumbelMaxDone = false; // = true after Gumbel (maximum order statistic) probability plot drawn + + private int logisticNumberOfParameters = 3; // number of Logistic parameters + private double[] logisticOrderMedians = null; // Logistic order statistic medians + private double[] logisticParam = null; // Logistic parameters obtained by the minimization procedure + private double[] logisticParamErrors = null; // estimates of the errors of the Logistic parameters obtained by the minimization procedure + private double logisticSumOfSquares = Double.NaN; // sum of squares at Logistic minimum + private double[] logisticLine = null; // Logistic probability plot gradient and intercept + private double[] logisticLineErrors = null; // estimated errors of the Logistic probability plot gradient and intercept + private double logisticCorrCoeff = Double.NaN; // Logistic correlation coefficient of the probability plot + private boolean logisticDone = false; // = true after Logistic probability plot drawn + + private int paretoNumberOfParameters = 2; // number of Pareto parameters + private double[] paretoOrderMedians = null; // Pareto order statistic medians + private double[] paretoParam = null; // Pareto parameters obtained by the minimization procedure + private double[] paretoParamErrors = null; // estimates of the errors of the Pareto parameters obtained by the minimization procedure + private double paretoSumOfSquares = Double.NaN; // sum of squares at Pareto minimum + private double[] paretoLine = null; // Pareto probability plot gradient and intercept + private double[] paretoLineErrors = null; // estimated errors of the Pareto probability plot gradient and intercept + private double paretoCorrCoeff = Double.NaN; // Pareto correlation coefficient of the probability plot + private boolean paretoDone = false; // = true after Pareto probability plot drawn + + private int rayleighNumberOfParameters = 2; // number of Rayleigh parameters + private double[] rayleighOrderMedians = null; // Rayleigh order statistic medians + private double[] rayleighParam = null; // Rayleigh parameters obtained by the minimization procedure + private double[] rayleighParamErrors = null; // estimates of the errors of the Rayleigh parameters obtained by the minimization procedure + private double rayleighSumOfSquares = Double.NaN; // sum of squares at Rayleigh minimum + private double[] rayleighLine = null; // Rayleigh probability plot gradient and intercept + private double[] rayleighLineErrors = null; // estimated errors of the Rayleigh probability plot gradient and intercept + private double rayleighCorrCoeff = Double.NaN; // Rayleigh correlation coefficient of the probability plot + private boolean rayleighDone = false; // = true after Rayleigh probability plot drawn + + private int weibullNumberOfParameters = 3; // number of Three Parameter Weibull parameters + private double[] weibullOrderMedians = null; // Three Parameter Weibull order statistic medians + private double[] weibullParam = null; // Three Parameter Weibull parameters obtained by the minimization procedure + private double[] weibullParamErrors = null; // estimates of the errors of the Three Parameter Weibull parameters obtained by the minimization procedure + private double weibullSumOfSquares = Double.NaN; // sum of squares at Three Parameter Weibull minimum + private double[] weibullLine = null; // Three Parameter Weibull probability plot gradient and intercept + private double[] weibullLineErrors = null; // estimated errors of the Three Parameter Weibull probability plot gradient and intercept + private double weibullCorrCoeff = Double.NaN; // Three Parameter Weibull correlation coefficient of the probability plot + private boolean weibullDone = false; // = true after Three Parameter Weibull probability plot drawn + + private int weibullTwoParNumberOfParameters = 2; // number of Two Parameter Weibull parameters + private double[] weibullTwoParOrderMedians = null; // Two Parameter Weibull order statistic medians + private double[] weibullTwoParParam = null; // Two Parameter Weibull parameters obtained by the minimization procedure + private double[] weibullTwoParParamErrors = null; // estimates of the errors of the Two Parameter Weibull parameters obtained by the minimization procedure + private double weibullTwoParSumOfSquares = Double.NaN; // sum of squares at Two Parameter Weibull minimum + private double[] weibullTwoParLine = null; // Two Parameter Weibull probability plot gradient and intercept + private double[] weibullTwoParLineErrors = null; // estimated errors of the Two Parameter Weibull probability plot gradient and intercept + private double weibullTwoParCorrCoeff = Double.NaN; // Two Parameter Weibull correlation coefficient of the probability plot + private boolean weibullTwoParDone = false; // = true after Two Parameter Weibull probability plot drawn + + private int weibullStandardNumberOfParameters = 1; // number of Standard Weibull parameters + private double[] weibullStandardOrderMedians = null; // Standard Weibull order statistic medians + private double[] weibullStandardParam = null; // Standard Weibull parameters obtained by the minimization procedure + private double[] weibullStandardParamErrors = null; // estimates of the errors of the Standard Weibull parameters obtained by the minimization procedure + private double weibullStandardSumOfSquares = Double.NaN;// sum of squares at Standard Weibull minimum + private double[] weibullStandardLine = null; // Standard Weibull probability plot gradient and intercept + private double[] weibullStandardLineErrors = null; // estimated errors of the Standard Weibull probability plot gradient and intercept + private double weibullStandardCorrCoeff = Double.NaN; // Standard Weibull correlation coefficient of the probability plot + private boolean weibullStandardDone = false; // = true after Standard Weibull probability plot drawn + private boolean probPlotDone = false; // = true after any probability plot drawn + + private double delta = 1e-3; // step fraction in numerical differentiation + + private boolean nFactorOptionI = false; // = true variance, covariance and standard deviation denominator = n // = false varaiance, covariance and standard deviation denominator = n-1 + private boolean nFactorReset = false; // = true when instance method resetting the denominator is called + + + + // CONSTRUCTORS + public ProbabilityPlot(double[] xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(Double[] xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(float[] xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(Float[] xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(long[] xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(Long[] xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(int[] xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(Integer[] xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(short[] xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(Short[] xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(byte[] xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(Byte[] xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(BigDecimal[] xx){ + this.arrayAsStat = new Stat(xx); + this.initialize(); + } + + public ProbabilityPlot(BigInteger[] xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(Object[] xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(Vector<Object> xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(ArrayList<Object> xx){ + this.arrayAsStat = new Stat(xx); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(ArrayMaths xx){ + this.arrayAsStat = xx.toStat(); + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + public ProbabilityPlot(Stat xx){ + this.arrayAsStat = xx; + this.array = this.arrayAsStat.array(); + this.initialize(); + } + + + // INITIALIZATIONS + private void initialize(){ + this.numberOfDataPoints = this.array.length; + Stat sorted = arrayAsStat.sort(); + this.sortedData = sorted.array(); + this.mean = arrayAsStat.mean(); + this.standardDeviation = arrayAsStat.standardDeviation(); + this.minimum = arrayAsStat.minimum(); + this.maximum = arrayAsStat.maximum(); + this.range = this.maximum - this.minimum; + this.weights = new double[this.numberOfDataPoints]; + for(int i=0; i<this.numberOfDataPoints; i++)weights[i] = 1.0; + } + + // WEIGHTING OPTION + // Set weighting option to weighted regression + public void weightedRegression(){ + this.weighted = true; + } + + // Set weighting option to unweighted regression + public void unweightedRegression(){ + this.weighted = false; + } + + // Get weighting option - String output + public String getWeightingOption(){ + if(this.weighted){ + return "Weighted Regression"; + } + else{ + return "Unweighted Regression"; + } + } + + // Get weighting option - boolean output + // returns true for weighted regression + // returns false for unweighted regression + public boolean getBooleanWeightingOption(){ + return this.weighted; + } + + // DATA SHIFT + // Tests if any negative or zero data points present and shifts data to positive domain + // Called by probability plot methods requiring all positive, non-zero data + private void negativeAndNonZeroDataShift(){ + this.dataShifted = false; + if(this.minimum<=0){ + this.dataOffset = this.range*0.01 - this.minimum; + this.dataShift(); + } + } + + + // Tests if any negative data points present and shifts data to positive domain + // Called by probability plot methods requiring all positive, non-zero data + private void negativeDataShift(){ + this.dataShifted = false; + if(this.minimum<0.0){ + this.dataOffset = -this.minimum; + this.dataShift(); + } + } + + // Shifts data + private void dataShift(){ + for(int i=0; i<this.numberOfDataPoints; i++){ + this.sortedData[i] += this.dataOffset; + } + this.minimum += this.dataOffset; + this.maximum += this.dataOffset; + this.mean += this.dataOffset; + this.dataShifted = true; + } + + // Returns data offset + public double getdataOffset(){ + return this.dataOffset; + } + + + + // rough estimate of the half-height peak width + private double peakWidth(){ + + this.halfWidth = 0.0; + double[] interpData = null; + int nInterp = 10000; + + // Interpolate to increase number of points to allow binning + if(this.numberOfDataPoints>=1000){ + interpData = this.sortedData; + nInterp = this.numberOfDataPoints; + } + else{ + double[] dataX = new double[this.numberOfDataPoints]; + for(int i=0; i<this.numberOfDataPoints; i++)dataX[i]=i; + double incrI = ((double)(this.numberOfDataPoints-1))/(nInterp-1); + + interpData = new double[nInterp]; + CubicSpline cs = new CubicSpline(dataX, this.sortedData); + double interp = 0.0; + for(int i=0; i<nInterp-1; i++){ + interpData[i]=cs.interpolate(interp); + interp += incrI; + + } + interpData[nInterp-1] = (double)(this.numberOfDataPoints-1); + } + + // Bin the data + int nBins = 100; + double[] binnedData = new double[nBins]; + double[] bins = new double[nBins]; + double binWidth = this.range/nBins; + double binLower = this.minimum; + double binUpper = binLower + binWidth; + int counter = 0; + for(int i=0; i<nBins; i++){ + bins[i] = (binUpper + binLower)/2.0; + binnedData[i] = 0.0; + boolean test = true; + if(counter>=nInterp)test = false; + while(test){ + if(interpData[counter]<binUpper){ + binnedData[i] += 1.0; + } + else{ + test = false; + } + counter++; + if(counter>=nInterp)test = false; + } + binLower = binUpper; + binUpper = binLower + binWidth; + } + if(counter<nInterp)binnedData[nBins-1] += (double)(nInterp-counter); + + // Identify peak + ArrayMaths am = new ArrayMaths(binnedData); + double maxI = am.maximum(); + int maxIindex = am.maximumIndex(); + this.peakPoint = bins[maxIindex]; + double halfHeight = maxI/2.0; + double widthLower = 0.0; + boolean lowerCheck = false; + double widthUpper = 0.0; + boolean upperCheck = false; + + // lower limit + if(binnedData[0]==halfHeight){ + widthLower = bins[0]; + lowerCheck = true; + } + else{ + if(binnedData[0]<halfHeight){ + if(maxIindex>=2){ + double[] interpLy = new double[maxIindex+1]; + double[] interpLx = new double[maxIindex+1]; + for(int i=0; i<=maxIindex; i++){ + interpLy[i] = binnedData[i]; + interpLx[i] = bins[i]; + } + CubicSpline csl = new CubicSpline(interpLx, interpLy); + double[] tempx = new double[100]; + double[] tempy = new double[100]; + double incr = (interpLx[maxIindex]-interpLx[0])/99; + double intr = interpLx[0]; + for(int i=0; i<99; i++){ + tempx[i] = intr; + tempy[i] = csl.interpolate(intr); + intr += incr; + } + tempy[99] = interpLy[maxIindex]; + tempx[99] = interpLx[maxIindex]; + boolean testt = true; + int ii = 0; + while(testt){ + if(halfHeight<=tempy[ii]){ + if(ii==0){ + widthLower = tempx[0]; + testt = false; + lowerCheck = true; + }else{ + if(ii==99){ + widthLower = tempx[99]; + testt = false; + lowerCheck = true; + } + else{ + widthLower = (tempx[ii] + tempx[ii-1])/2.0; + testt = false; + lowerCheck = true; + } + } + } + ii++; + if(ii>=100)testt = false; + } + } + else{ + if(maxIindex==2){ + if(binnedData[1]>=halfHeight){ + widthLower = bins[0] + (bins[1] - bins[0])*(halfHeight - binnedData[0])/(binnedData[1] - binnedData[0]); + lowerCheck = true; + } + else{ + widthLower = bins[1] + (bins[2] - bins[1])*(halfHeight - binnedData[1])/(binnedData[2] - binnedData[1]); + lowerCheck = true; + } + } + else{ + widthLower = bins[0] + (bins[1] - bins[0])*(halfHeight - binnedData[0])/(binnedData[1] - binnedData[0]); + lowerCheck = true; + } + } + } + else{ + if(maxIindex>2){ + if((binnedData[maxIindex]-binnedData[0])>halfHeight*0.5){ + widthLower = bins[0] + (bins[1] - bins[0])*(halfHeight - binnedData[0])/(binnedData[1] - binnedData[0]); + lowerCheck = true; + } + } + } + } + + // upper limit + int nTop = nBins - 1; + int nDif = nBins - maxIindex; + if(binnedData[nTop]==halfHeight){ + widthUpper = bins[nTop]; + upperCheck = true; + } + else{ + if(binnedData[nTop]<halfHeight){ + if(nDif>=3){ + double[] interpLy = new double[nDif]; + double[] interpLx = new double[nDif]; + int ii = 0; + for(int i=maxIindex; i<nBins; i++){ + interpLy[ii] = binnedData[i]; + interpLx[ii] = bins[i]; + ii++; + } + CubicSpline csl = new CubicSpline(interpLx, interpLy); + double[] tempx = new double[100]; + double[] tempy = new double[100]; + double incr = (interpLx[nDif-1]-interpLx[0])/99; + double intr = interpLx[0]; + for(int i=0; i<99; i++){ + tempx[i] = intr; + tempy[i] = csl.interpolate(intr); + intr += incr; + } + tempy[99] = interpLy[nDif-1]; + tempx[99] = interpLx[nDif-1]; + boolean testt = true; + ii = 0; + while(testt){ + if(halfHeight<=tempy[ii]){ + if(ii==0){ + widthUpper = tempx[0]; + testt = false; + upperCheck = true; + }else{ + if(ii==99){ + widthUpper = tempx[99]; + testt = false; + upperCheck = true; + } + else{ + widthUpper = (tempx[ii] + tempx[ii-1])/2.0; + testt = false; + upperCheck = true; + } + } + } + ii++; + if(ii>=100)testt = false; + } + } + else{ + if(nDif==2){ + if(binnedData[nTop-1]>=halfHeight){ + widthUpper = bins[nTop-1] + (bins[nTop] - bins[nTop-1])*(halfHeight - binnedData[nTop-1])/(binnedData[nTop] - binnedData[nTop-1]); + upperCheck = true; + } + else{ + widthUpper = bins[nTop-2] + (bins[nTop-1] - bins[nTop-2])*(halfHeight - binnedData[nTop-2])/(binnedData[nTop-1] - binnedData[nTop-2]); + upperCheck = true; + } + } + else{ + widthUpper = bins[nTop-1] + (bins[nTop] - bins[nTop-1])*(halfHeight - binnedData[nTop-1])/(binnedData[nTop] - binnedData[nTop-1]); + upperCheck = true; + } + } + } + else{ + if(nDif>2){ + if((binnedData[maxIindex]-binnedData[nTop])>halfHeight*0.5){ + widthUpper = bins[nTop-1] + (bins[nTop] - bins[nTop-1])*(halfHeight - binnedData[nTop-1])/(binnedData[nTop] - binnedData[nTop-1]); + upperCheck = true; + } + } + } + } + + // combine lower and upper half widths + if(lowerCheck){ + if(upperCheck){ + this.halfWidth = widthUpper - widthLower; + } + else{ + this.halfWidth = (this.peakPoint - widthLower)*1.3; + } + } + else{ + if(upperCheck){ + this.halfWidth = (widthUpper - this.peakPoint)*1.3; + } + else{ + System.out.println("Half height width could not be calculated - half range returned"); + this.halfWidth = this.range/2.0; + } + + } + return this.halfWidth; + } + + // GAUSSIAN PROBABILITY PLOT + public void gaussianProbabilityPlot(){ + this.lastMethod = 0; + + // Check for suffient data points + this.gaussianNumberOfParameters = 2; + if(this.numberOfDataPoints<3)throw new IllegalArgumentException("There must be at least three data points - preferably considerably more"); + + // Create instance of Regression + Regression min = new Regression(this.sortedData, this.sortedData); + double meanest = this.mean; + if(this.mean==0)meanest = this.standardDeviation/3.0; + double[] start = {meanest, this.standardDeviation}; + this.initialEstimates = start; + double[] step = {0.3*meanest, 0.3*this.standardDeviation}; + double tolerance = 1e-10; + + // Add constraint; sigma>0 + min.addConstraint(1, -1, 0); + + // Create an instance of GaussProbPlotFunc + GaussProbPlotFunc gppf = new GaussProbPlotFunc(); + gppf.setDataArray(this.numberOfDataPoints); + + // Obtain best probability plot varying mu and sigma + // by minimizing the sum of squares of the differences between the ordered data and the ordered statistic medians + min.simplex(gppf, start, step, tolerance); + + // Get mu and sigma for best correlation coefficient + this.gaussianParam = min.getBestEstimates(); + + // Get mu and sigma errors for best correlation coefficient + this.gaussianParamErrors = min.getBestEstimatesErrors(); + + // Calculate Gaussian order statistic medians + this.gaussianOrderMedians = Stat.gaussianOrderStatisticMedians(this.gaussianParam[0], this.gaussianParam[1], this.numberOfDataPoints); + + // Regression of the ordered data on the Gaussian order statistic medians + Regression reg = new Regression(this.gaussianOrderMedians, this.sortedData); + reg.linear(); + + // Intercept and gradient of best fit straight line + this.gaussianLine = reg.getBestEstimates(); + + // Estimated erors of the intercept and gradient of best fit straight line + this.gaussianLineErrors = reg.getBestEstimatesErrors(); + + // Correlation coefficient + this.gaussianCorrCoeff = reg.getSampleR(); + + // Initialize data arrays for plotting + double[][] data = PlotGraph.data(2,this.numberOfDataPoints); + + // Assign data to plotting arrays + data[0] = this.gaussianOrderMedians; + data[1] = this.sortedData; + + data[2] = this.gaussianOrderMedians; + for(int i=0; i<this.numberOfDataPoints; i++){ + data[3][i] = this.gaussianLine[0] + this.gaussianLine[1]*this.gaussianOrderMedians[i]; + } + + // Get sum of squares + this.gaussianSumOfSquares = min.getSumOfSquares(); + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("Gaussian Order Statistic Medians"); + pg.setYaxisLegend("Ordered Data Values"); + pg.setGraphTitle("Gaussian probability plot: gradient = " + Fmath.truncate(this.gaussianLine[1], 4) + ", intercept = " + Fmath.truncate(this.gaussianLine[0], 4) + ", R = " + Fmath.truncate(this.gaussianCorrCoeff, 4)); + pg.setGraphTitle2(" mu = " + Fmath.truncate(this.gaussianParam[0], 4) + ", sigma = " + Fmath.truncate(this.gaussianParam[1], 4)); + + // Plot + pg.plot(); + + this.gaussianDone = true; + } + + public void normalProbabilityPlot(){ + this.gaussianProbabilityPlot(); + } + + // Return Gaussian mu + public double gaussianMu(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianParam[0]; + } + + // Return Gaussian mu error + public double gaussianMuError(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianParamErrors[0]; + } + + // Return Gaussian sigma + public double gaussianSigma(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianParam[1]; + } + + // Return Gaussian sigma error + public double gaussianSigmaError(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianParamErrors[1]; + } + + // Return the Gaussian gradient + public double gaussianGradient(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianLine[1]; + } + + // Return the error of the Gaussian gradient + public double gaussianGradientError(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianLineErrors[1]; + } + + // Return the Gaussian intercept + public double gaussianIntercept(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianLine[0]; + } + + // Return the error of the Gaussian intercept + public double gaussianInterceptError(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianLineErrors[0]; + } + + // Return the Gaussian correlation coefficient + public double gaussianCorrelationCoefficient(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianCorrCoeff; + } + + // Return the sum of squares at the Gaussian minimum + public double gaussianSumOfSquares(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianSumOfSquares; + } + + // Return the unweighted sum of squares at the Gaussian minimum + public double gaussianUnweightedSumOfSquares(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianUnweightedSumOfSquares; + } + + + // Return Gaussian order statistic medians + public double[] gaussianOrderStatisticMedians(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianOrderMedians; + } + + + public double normalMu(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianParam[0]; + } + + // Return Gaussian mu error + public double normalMuError(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianParamErrors[0]; + } + + // Return Gaussian sigma + public double normalSigma(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianParam[1]; + } + + // Return Gaussian sigma error + public double normalSigmaError(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianParamErrors[1]; + } + + // Return the Gaussian gradient + public double normalGradient(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianLine[1]; + } + + // Return the error of the Gaussian gradient + public double normalGradientError(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianLineErrors[1]; + } + + // Return the Gaussian intercept + public double normalIntercept(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianLine[0]; + } + + // Return the error of the Gaussian intercept + public double normalInterceptError(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianLineErrors[0]; + } + + // Return the Gaussian correlation coefficient + public double normalCorrelationCoefficient(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianCorrCoeff; + } + + // Return the sum of squares at the Gaussian minimum + public double normalSumOfSquares(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianSumOfSquares; + } + + // Return Gaussian order statistic medians + public double[] normalOrderStatisticMedians(){ + if(!this.gaussianDone)throw new IllegalArgumentException("Gaussian Probability Plot method has not been called"); + return this.gaussianOrderMedians; + } + + + + // STANDARD GAUSSIAN PROBABILITY PLOT + public void gaussianStandardProbabilityPlot(){ + this.lastMethod = 14; + + // Check for suffient data points + this.gaussianStandardNumberOfParameters = 2; + if(this.numberOfDataPoints<3)throw new IllegalArgumentException("There must be at least three data points - preferably considerably more"); + + // Calculate Standard Gaussian order statistic medians + this.gaussianStandardOrderMedians = Stat.gaussianOrderStatisticMedians(this.numberOfDataPoints); + + // Regression of the ordered data on the Standard Gaussian order statistic medians + Regression reg = new Regression(this.gaussianStandardOrderMedians, this.sortedData); + reg.linear(); + + // Intercept and gradient of best fit straight line + this.gaussianStandardLine = reg.getBestEstimates(); + + // Estimated erors of the intercept and gradient of best fit straight line + this.gaussianStandardLineErrors = reg.getBestEstimatesErrors(); + + // Correlation coefficient + this.gaussianStandardCorrCoeff = reg.getSampleR(); + + // Initialize data arrays for plotting + double[][] data = PlotGraph.data(2,this.numberOfDataPoints); + + // Assign data to plotting arrays + data[0] = this.gaussianStandardOrderMedians; + data[1] = this.sortedData; + + data[2] = this.gaussianStandardOrderMedians; + for(int i=0; i<this.numberOfDataPoints; i++){ + data[3][i] = this.gaussianStandardLine[0] + this.gaussianStandardLine[1]*this.gaussianStandardOrderMedians[i]; + } + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("Standard Gaussian Order Statistic Medians"); + pg.setYaxisLegend("Ordered Data Values"); + pg.setGraphTitle("Standard Gaussian probability plot: gradient = " + Fmath.truncate(this.gaussianStandardLine[1], 4) + ", intercept = " + Fmath.truncate(this.gaussianStandardLine[0], 4) + ", R = " + Fmath.truncate(this.gaussianStandardCorrCoeff, 4)); + + // Plot + pg.plot(); + + this.gaussianStandardDone = true; + } + + public void normalStandardProbabilityPlot(){ + this.gaussianStandardProbabilityPlot(); + } + + // Return the Standard Gaussian gradient + public double gaussianStandardGradient(){ + if(!this.gaussianStandardDone)throw new IllegalArgumentException("Standard Gaussian Probability Plot method has not been called"); + return this.gaussianStandardLine[1]; + } + + // Return the error of the Standard Gaussian gradient + public double gaussianStandardGradientError(){ + if(!this.gaussianStandardDone)throw new IllegalArgumentException("Standard Gaussian Probability Plot method has not been called"); + return this.gaussianStandardLineErrors[1]; + } + + // Return the Standard Gaussian intercept + public double gaussianStandardIntercept(){ + if(!this.gaussianStandardDone)throw new IllegalArgumentException("Standard Gaussian Probability Plot method has not been called"); + return this.gaussianStandardLine[0]; + } + + // Return the error of the Standard Gaussian intercept + public double gaussianStandardInterceptError(){ + if(!this.gaussianStandardDone)throw new IllegalArgumentException("Standard Gaussian Probability Plot method has not been called"); + return this.gaussianStandardLineErrors[0]; + } + + // Return the Standard Gaussian correlation coefficient + public double gaussianStandardCorrelationCoefficient(){ + if(!this.gaussianStandardDone)throw new IllegalArgumentException("Standard Gaussian Probability Plot method has not been called"); + return this.gaussianStandardCorrCoeff; + } + + // Return the sum of squares at the Standard Gaussian minimum + public double gaussianStandardSumOfSquares(){ + if(!this.gaussianStandardDone)throw new IllegalArgumentException("Standard Gaussian Probability Plot method has not been called"); + return this.gaussianStandardSumOfSquares; + } + + // Return Standard Gaussian order statistic medians + public double[] gaussianStandardOrderStatisticMedians(){ + if(!this.gaussianStandardDone)throw new IllegalArgumentException("Standard Gaussian Probability Plot method has not been called"); + return this.gaussianStandardOrderMedians; + } + + + // Return the Standard Gaussian gradient + public double normalStandardGradient(){ + if(!this.gaussianStandardDone)throw new IllegalArgumentException("Standard Gaussian Probability Plot method has not been called"); + return this.gaussianStandardLine[1]; + } + + // Return the error of the Standard Gaussian gradient + public double normalstandardGradientError(){ + if(!this.gaussianStandardDone)throw new IllegalArgumentException("Standard Gaussian Probability Plot method has not been called"); + return this.gaussianStandardLineErrors[1]; + } + + // Return the Standard Gaussian intercept + public double normalStandardInterceptError(){ + if(!this.gaussianStandardDone)throw new IllegalArgumentException("Standard Gaussian Probability Plot method has not been called"); + return this.gaussianStandardLineErrors[0]; + } + + // Return the Standard Gaussian correlation coefficient + public double normalStandardCorrelationCoefficient(){ + if(!this.gaussianStandardDone)throw new IllegalArgumentException("Standard Gaussian Probability Plot method has not been called"); + return this.gaussianStandardCorrCoeff; + } + + // Return the sum of squares at the Standard Gaussian minimum + public double normalStandardSumOfSquares(){ + if(!this.gaussianStandardDone)throw new IllegalArgumentException("Standard Gaussian Probability Plot method has not been called"); + return this.gaussianStandardSumOfSquares; + } + + // Return Standard Gaussian order statistic medians + public double[] normalStandardOrderStatisticMedians(){ + if(!this.gaussianStandardDone)throw new IllegalArgumentException("Standard Gaussian Probability Plot method has not been called"); + return this.gaussianStandardOrderMedians; + } + + // LOGISTIC PROBABILITY PLOT + public void logisticProbabilityPlot(){ + this.lastMethod = 8; + + // Check for suffient data points + this.logisticNumberOfParameters = 2; + if(this.numberOfDataPoints<3)throw new IllegalArgumentException("There must be at least three data points - preferably considerably more"); + + // Create instance of Regression + Regression min = new Regression(this.sortedData, this.sortedData); + double muest = mean; + if(muest==0.0)muest = this.standardDeviation/3.0; + double betaest = this.standardDeviation; + double[] start = {muest, betaest}; + this.initialEstimates = start; + double[] step = {0.3*muest, 0.3*betaest}; + double tolerance = 1e-10; + + // Add constraint; beta>0 + min.addConstraint(1, -1, 0); + + // Create an instance of LogisticProbPlotFunc + LogisticProbPlotFunc lppf = new LogisticProbPlotFunc(); + lppf.setDataArray(this.numberOfDataPoints); + + // Obtain best probability plot varying mu and sigma + // by minimizing the sum of squares of the differences between the ordered data and the ordered statistic medians + min.simplex(lppf, start, step, tolerance); + + // Get mu and beta for best correlation coefficient + this.logisticParam = min.getBestEstimates(); + + // Get mu and beta errors for best correlation coefficient + this.logisticParamErrors = min.getBestEstimatesErrors(); + + // Get sum of squares + this.logisticSumOfSquares = min.getSumOfSquares(); + + // Calculate Logistic order statistic medians + this.logisticOrderMedians = Stat.logisticOrderStatisticMedians(this.logisticParam[0], this.logisticParam[1], this.numberOfDataPoints); + + // Regression of the ordered data on the Logistic order statistic medians + Regression reg = new Regression(this.logisticOrderMedians, this.sortedData); + reg.linear(); + + // Intercept and gradient of best fit straight line + this.logisticLine = reg.getBestEstimates(); + + // Estimated erors of the intercept and gradient of best fit straight line + this.logisticLineErrors = reg.getBestEstimatesErrors(); + + // Correlation coefficient + this.logisticCorrCoeff = reg.getSampleR(); + + // Initialize data arrays for plotting + double[][] data = PlotGraph.data(2,this.numberOfDataPoints); + + // Assign data to plotting arrays + data[0] = this.logisticOrderMedians; + data[1] = this.sortedData; + + data[2] = logisticOrderMedians; + for(int i=0; i<this.numberOfDataPoints; i++){ + data[3][i] = this.logisticLine[0] + this.logisticLine[1]*logisticOrderMedians[i]; + } + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("Logistic Order Statistic Medians"); + pg.setYaxisLegend("Ordered Data Values"); + pg.setGraphTitle("Logistic probability plot: gradient = " + Fmath.truncate(this.logisticLine[1], 4) + ", intercept = " + Fmath.truncate(this.logisticLine[0], 4) + ", R = " + Fmath.truncate(this.logisticCorrCoeff, 4)); + pg.setGraphTitle2(" mu = " + Fmath.truncate(this.logisticParam[0], 4) + ", beta = " + Fmath.truncate(this.logisticParam[1], 4)); + + // Plot + pg.plot(); + + this.logisticDone = true; + this.probPlotDone = true; + } + + // Return Logistic mu + public double logisticMu(){ + if(!this.logisticDone)throw new IllegalArgumentException("Logistic Probability Plot method has not been called"); + return this.logisticParam[0]; + } + + // Return Logistic mu error + public double logisticMuError(){ + if(!this.logisticDone)throw new IllegalArgumentException("Logistic Probability Plot method has not been called"); + return this.logisticParamErrors[0]; + } + + // Return Logistic beta + public double logisticBeta(){ + if(!this.logisticDone)throw new IllegalArgumentException("Logistic Probability Plot method has not been called"); + return this.logisticParam[1]; + } + + // Return Logistic beta error + public double logisticBetaError(){ + if(!this.logisticDone)throw new IllegalArgumentException("Logistic Probability Plot method has not been called"); + return this.logisticParamErrors[1]; + } + + // Return Logistic order statistic medians + public double[] logisticOrderStatisticMedians(){ + if(!this.logisticDone)throw new IllegalArgumentException("Logistic Probability Plot method has not been called"); + return this.logisticOrderMedians; + } + + // Return the Logistic gradient + public double logisticGradient(){ + if(!this.logisticDone)throw new IllegalArgumentException("Logistic Probability Plot method has not been called"); + return this.logisticLine[1]; + } + + // Return the error of the Logistic gradient + public double logisticGradientError(){ + if(!this.logisticDone)throw new IllegalArgumentException("Logistic Probability Plot method has not been called"); + return this.logisticLineErrors[1]; + } + + // Return the Logistic intercept + public double logisticIntercept(){ + if(!this.logisticDone)throw new IllegalArgumentException("Logistic Probability Plot method has not been called"); + return this.logisticLine[0]; + } + + // Return the error of the Logistic intercept + public double logisticInterceptError(){ + if(!this.logisticDone)throw new IllegalArgumentException("Logistic Probability Plot method has not been called"); + return this.logisticLineErrors[0]; + } + + // Return the Logistic correlation coefficient + public double logisticCorrelationCoefficient(){ + if(!this.logisticDone)throw new IllegalArgumentException("Logistic Probability Plot method has not been called"); + return this.logisticCorrCoeff; + } + + // Return the sum of squares at the Logistic minimum + public double logisticSumOfSquares(){ + if(!this.logisticDone)throw new IllegalArgumentException("Logistic Probability Plot method has not been called"); + return this.logisticSumOfSquares; + } + + + + // WEIBULL PROBABILITY PLOT + // Three parameter + public void weibullProbabilityPlot(){ + this.lastMethod = 1; + + // Check for suffient data points + this.weibullNumberOfParameters = 3; + if(this.numberOfDataPoints<4)throw new IllegalArgumentException("There must be at least four data points - preferably considerably more"); + + // Create instance of Regression + Regression min = new Regression(this.sortedData, this.sortedData); + + // Calculate initial estimates + double[] start = new double[3]; + start[0] = this.minimum - 0.1*Math.abs(this.minimum); + start[1] = this.peakWidth(); + start[2] = 4.0; + this.initialEstimates = start; + double[] step = {Math.abs(0.3*start[0]), Math.abs(0.3*start[1]), Math.abs(0.3*start[2])}; + if(step[0]==0)step[0] = this.range*0.01; + double tolerance = 1e-10; + + // Add constraint; mu<minimum, sigma>0, gamma>0 + min.addConstraint(0, +1, minimum); + min.addConstraint(1, -1, 0); + min.addConstraint(2, -1, 0); + + // Create an instance of WeibullProbPlotFunc + WeibullProbPlotFunc wppf = new WeibullProbPlotFunc(); + wppf.setDataArray(this.numberOfDataPoints); + + // Obtain best probability plot varying mu, sigma and gamma + // by minimizing the sum of squares of the differences between the ordered data and the ordered statistic medians + min.simplex(wppf, start.clone(), step, tolerance); + + // Obtain best estimates or first minimisation + double[] firstBests = min.getBestEstimates(); + + // Get mu and sigma value errors + double[] firstErrors = min.getBestEstimatesErrors(); + + // Get sum of squares + double ss = min.getSumOfSquares(); + + //Calculate new initial estimates + double[] start2 = new double[this.weibullNumberOfParameters]; + start2[0] = 2.0*firstBests[0] - start[0]; + if(start2[0]>minimum)start2[0] = minimum*(1.0 - Math.abs(minimum)*0.05); + step[0] = Math.abs(start2[0]*0.1); + if(step[0]==0)step[0] = this.range*0.01; + start2[1] = 2.0*firstBests[1] - start[1]; + if(start2[1]<=0.0)start2[1] = Math.abs(2.0*firstBests[1] - 0.98*start[1]); + step[1] = Math.abs(start2[1]*0.1); + start2[2] = 2.0*firstBests[2] - start[2]; + if(start2[1]<=0.0)start2[2] = Math.abs(2.0*firstBests[2] - 0.98*start[2]); + step[2] = Math.abs(start2[2]*0.1); + + min.simplex(wppf, start2.clone(), step, tolerance); + + // Get mu, sigma and gamma for best correlation coefficient + this.weibullParam = min.getBestEstimates(); + + // Get mu and sigma value errors + this.weibullParamErrors = min.getBestEstimatesErrors(); + + // Get sum of squares + this.weibullSumOfSquares = min.getSumOfSquares(); + + if(ss<this.weibullSumOfSquares){ + this.weibullParam = firstBests; + this.weibullParamErrors = firstErrors; + this.weibullSumOfSquares = ss; + } + + // Calculate Weibull order statistic medians + this.weibullOrderMedians = Stat.weibullOrderStatisticMedians(this.weibullParam[0], this.weibullParam[1], this.weibullParam[2], this.numberOfDataPoints); + + // Regression of the ordered data on the Weibull order statistic medians + Regression reg = new Regression(this.weibullOrderMedians, this.sortedData); + reg.linear(); + + // Intercept and gradient of best fit straight line + this.weibullLine = reg.getBestEstimates(); + + // Estimated erors of the intercept and gradient of best fit straight line + this.weibullLineErrors = reg.getBestEstimatesErrors(); + + // Correlation coefficient + this.weibullCorrCoeff = reg.getSampleR(); + + // Initialize data arrays for plotting + double[][] data = PlotGraph.data(2,this.numberOfDataPoints); + + // Assign data to plotting arrays + data[0] = this.weibullOrderMedians; + data[1] = this.sortedData; + + data[2] = weibullOrderMedians; + for(int i=0; i<this.numberOfDataPoints; i++){ + data[3][i] = this.weibullLine[0] + this.weibullLine[1]*weibullOrderMedians[i]; + } + + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("Weibull Order Statistic Medians"); + pg.setYaxisLegend("Ordered Data Values"); + pg.setGraphTitle("Weibull probability plot: gradient = " + Fmath.truncate(this.weibullLine[1], 4) + ", intercept = " + Fmath.truncate(this.weibullLine[0], 4) + ", R = " + Fmath.truncate(this.weibullCorrCoeff, 4)); + pg.setGraphTitle2(" mu = " + Fmath.truncate(this.weibullParam[0], 4) + ", sigma = " + Fmath.truncate(this.weibullParam[1], 4) + ", gamma = " + Fmath.truncate(this.weibullParam[2], 4)); + + // Plot + pg.plot(); + + this.weibullDone = true; + this.probPlotDone = true; + } + + // WEIBULL PROBABILITY PLOT + // Three parameter + public void weibullThreeParProbabilityPlot(){ + this.weibullProbabilityPlot(); + } + + // Return Weibull mu + public double weibullMu(){ + if(!this.weibullDone)throw new IllegalArgumentException("Weibull Probability Plot method has not been called"); + return this.weibullParam[0]; + } + + // Return Weibull mu error + public double weibullMuError(){ + if(!this.weibullDone)throw new IllegalArgumentException("Weibull Probability Plot method has not been called"); + return this.weibullParamErrors[0]; + } + + // Return Weibull sigma + public double weibullSigma(){ + if(!this.weibullDone)throw new IllegalArgumentException("Weibull Probability Plot method has not been called"); + return this.weibullParam[1]; + } + + // Return Weibull sigma error + public double weibullSigmaError(){ + if(!this.weibullDone)throw new IllegalArgumentException("Weibull Probability Plot method has not been called"); + return this.weibullParamErrors[1]; + } + + // Return Weibull gamma + public double weibullGamma(){ + if(!this.weibullDone)throw new IllegalArgumentException("Weibull Probability Plot method has not been called"); + return this.weibullParam[2]; + } + + // Return Weibull gamma error + public double weibullGammaError(){ + if(!this.weibullDone)throw new IllegalArgumentException("Weibull Probability Plot method has not been called"); + return this.weibullParamErrors[2]; + } + + // Return Weibull order statistic medians + public double[] weibullOrderStatisticMedians(){ + if(!this.weibullDone)throw new IllegalArgumentException("Weibull Probability Plot method has not been called"); + return this.weibullOrderMedians; + } + + // Return the Weibull gradient + public double weibullGradient(){ + if(!this.weibullDone)throw new IllegalArgumentException("Weibull Probability Plot method has not been called"); + return this.weibullLine[1]; + } + + // Return the error of the Weibull gradient + public double weibullGradientError(){ + if(!this.weibullDone)throw new IllegalArgumentException("Weibull Probability Plot method has not been called"); + return this.weibullLineErrors[1]; + } + + // Return the Weibull intercept + public double weibullIntercept(){ + if(!this.weibullDone)throw new IllegalArgumentException("Weibull Probability Plot method has not been called"); + return this.weibullLine[0]; + } + + // Return the error of the Weibull intercept + public double weibullInterceptError(){ + if(!this.weibullDone)throw new IllegalArgumentException("Weibull Probability Plot method has not been called"); + return this.weibullLineErrors[0]; + } + + // Return the Weibull correlation coefficient + public double weibullCorrelationCoefficient(){ + if(!this.weibullDone)throw new IllegalArgumentException("Weibull Probability Plot method has not been called"); + return this.weibullCorrCoeff; + } + + // Return the sum of squares at the Weibull minimum + public double weibullSumOfSquares(){ + if(!this.weibullDone)throw new IllegalArgumentException("Weibull Probability Plot method has not been called"); + return this.weibullSumOfSquares; + } + + // WEIBULL PROBABILITY PLOT + // Two parameter (mu = 0) + public void weibullTwoParProbabilityPlot(){ + this.lastMethod = 12; + + // Check for negative x values + if(this.sortedData[0]<0){ + System.out.println("Method weibullTwoParProbabilityPlot: negative x value found - weibullThreeParProbabilityPlot called"); + this.weibullThreeParProbabilityPlot(); + } + + // Check data for suffient points + this.weibullTwoParNumberOfParameters = 2; + if(this.numberOfDataPoints<3)throw new IllegalArgumentException("There must be at least three data points - preferably considerably more"); + + // Create instance of Regression + Regression min = new Regression(this.sortedData, this.sortedData); + + // Calculate initial estimates + double[] start = new double[2]; + start[0] = this.peakWidth(); + start[1] = 4.0; + this.initialEstimates = start; + double[] step = {Math.abs(0.3*start[0]), Math.abs(0.3*start[1])}; + if(step[0]==0)step[0] = this.range*0.01; + double tolerance = 1e-10; + + // Add constraint; sigma>0, gamma>0 + min.addConstraint(0, -1, 0); + min.addConstraint(1, -1, 0); + + // Create an instance of WeibullTwoParProbPlotFunc + WeibullTwoParProbPlotFunc wppf = new WeibullTwoParProbPlotFunc(); + wppf.setDataArray(this.numberOfDataPoints); + + // Obtain best probability plot varying sigma and gamma + // by minimizing the sum of squares of the differences between the ordered data and the ordered statistic medians + min.simplex(wppf, start.clone(), step, tolerance); + + // Obtain best estimates or first minimisation + double[] firstBests = min.getBestEstimates(); + + // Get mu and sigma value errors + double[] firstErrors = min.getBestEstimatesErrors(); + + // Get sum of squares + double ss = min.getSumOfSquares(); + + //Calculate new initial estimates + double[] start2 = new double[this.weibullTwoParNumberOfParameters]; + start2[0] = 2.0*firstBests[0] - start[0]; + if(start2[0]>minimum)start2[0] = minimum*(1.0 - Math.abs(minimum)*0.05); + step[0] = Math.abs(start2[0]*0.1); + if(step[0]==0)step[0] = this.range*0.01; + start2[1] = 2.0*firstBests[1] - start[1]; + if(start2[1]<=0.0)start2[1] = Math.abs(2.0*firstBests[1] - 0.98*start[1]); + step[1] = Math.abs(start2[1]*0.1); + + min.simplex(wppf, start2.clone(), step, tolerance); + + // Get sigma and gamma for best correlation coefficient + this.weibullTwoParParam = min.getBestEstimates(); + + // Get sigma and gamma value errors + this.weibullTwoParParamErrors = min.getBestEstimatesErrors(); + + // Get sum of squares + this.weibullTwoParSumOfSquares = min.getSumOfSquares(); + + if(ss<this.weibullSumOfSquares){ + this.weibullTwoParParam = firstBests; + this.weibullTwoParParamErrors = firstErrors; + this.weibullTwoParSumOfSquares = ss; + } + + // Calculate WeibullTwoPar order statistic medians + this.weibullTwoParOrderMedians = Stat.weibullOrderStatisticMedians(this.weibullTwoParParam[0], this.weibullTwoParParam[1], this.numberOfDataPoints); + + // Regression of the ordered data on the Weibull order statistic medians + Regression reg = new Regression(this.weibullTwoParOrderMedians, this.sortedData); + reg.linear(); + + // Intercept and gradient of best fit straight line + this.weibullTwoParLine = reg.getBestEstimates(); + + // Estimated erors of the intercept and gradient of best fit straight line + this.weibullTwoParLineErrors = reg.getBestEstimatesErrors(); + + // Correlation coefficient + this.weibullTwoParCorrCoeff = reg.getSampleR(); + + // Initialize data arrays for plotting + double[][] data = PlotGraph.data(2,this.numberOfDataPoints); + + // Assign data to plotting arrays + data[0] = this.weibullTwoParOrderMedians; + data[1] = this.sortedData; + + data[2] = weibullTwoParOrderMedians; + for(int i=0; i<this.numberOfDataPoints; i++){ + data[3][i] = this.weibullTwoParLine[0] + this.weibullTwoParLine[1]*weibullTwoParOrderMedians[i]; + } + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("Weibull Order Statistic Medians"); + pg.setYaxisLegend("Ordered Data Values"); + pg.setGraphTitle("Two Parameter Weibull probability plot: gradient = " + Fmath.truncate(this.weibullTwoParLine[1], 4) + ", intercept = " + Fmath.truncate(this.weibullTwoParLine[0], 4) + ", R = " + Fmath.truncate(this.weibullTwoParCorrCoeff, 4)); + pg.setGraphTitle2(" mu = 0, sigma = " + Fmath.truncate(this.weibullTwoParParam[0], 4) + ", gamma = " + Fmath.truncate(this.weibullTwoParParam[1], 4)); + + // Plot + pg.plot(); + + this.weibullTwoParDone = true; + this.probPlotDone = true; + } + + // Return Two Parameter Weibull sigma + public double weibullTwoParSigma(){ + if(!this.weibullTwoParDone)throw new IllegalArgumentException("Two Parameter Weibull Probability Plot method has not been called"); + return this.weibullTwoParParam[0]; + } + + // Return Two Parameter Weibull sigma error + public double weibullTwoParSigmaError(){ + if(!this.weibullTwoParDone)throw new IllegalArgumentException("Two Parameter Weibull Probability Plot method has not been called"); + return this.weibullTwoParParamErrors[0]; + } + + // Return Two Parameter Weibull gamma + public double weibullTwoParGamma(){ + if(!this.weibullTwoParDone)throw new IllegalArgumentException("Two Parameter Weibull Probability Plot method has not been called"); + return this.weibullTwoParParam[1]; + } + + // Return Two Parameter Weibull gamma error + public double weibullTwoParGammaError(){ + if(!this.weibullTwoParDone)throw new IllegalArgumentException("Two Parameter Weibull Probability Plot method has not been called"); + return this.weibullTwoParParamErrors[1]; + } + + // Return Two Parameter Weibull order statistic medians + public double[] weibullTwoParOrderStatisticMedians(){ + if(!this.weibullTwoParDone)throw new IllegalArgumentException("Two Parameter Weibull Probability Plot method has not been called"); + return this.weibullTwoParOrderMedians; + } + + // Return the Two Parameter Weibull gradient + public double weibullTwoParGradient(){ + if(!this.weibullTwoParDone)throw new IllegalArgumentException("Two Parameter Weibull Probability Plot method has not been called"); + return this.weibullTwoParLine[1]; + } + + // Return the error of the Two Parameter Weibull gradient + public double weibullTwoParGradientError(){ + if(!this.weibullTwoParDone)throw new IllegalArgumentException("Two Parameter Weibull Probability Plot method has not been called"); + return this.weibullTwoParLineErrors[1]; + } + + // Return the Two Parameter Weibull intercept + public double weibullTwoParIntercept(){ + if(!this.weibullTwoParDone)throw new IllegalArgumentException("Two Parameter Weibull Probability Plot method has not been called"); + return this.weibullTwoParLine[0]; + } + + // Return the error of the Two Parameter Weibull intercept + public double weibullTwoParInterceptError(){ + if(!this.weibullTwoParDone)throw new IllegalArgumentException("Two Parameter Weibull Probability Plot method has not been called"); + return this.weibullTwoParLineErrors[0]; + } + + // Return the Two Parameter Weibull correlation coefficient + public double weibullTwoParCorrelationCoefficient(){ + if(!this.weibullTwoParDone)throw new IllegalArgumentException("Two Parameter Weibull Probability Plot method has not been called"); + return this.weibullTwoParCorrCoeff; + } + + // Return the sum of squares at the Two Parameter Weibull minimum + public double weibullTwoParSumOfSquares(){ + if(!this.weibullTwoParDone)throw new IllegalArgumentException("Two Parameter Weibull Probability Plot method has not been called"); + return this.weibullTwoParSumOfSquares; + } + + // WEIBULL PROBABILITY PLOT + // Standard (one parameter) (mu = 0, sigma =1) + public void weibullStandardProbabilityPlot(){ + this.lastMethod = 13; + + // Check for negative x values + if(this.sortedData[0]<0){ + System.out.println("Method weibullStandardProbabilityPlot: negative x value found - weibullThreeParProbabilityPlot called"); + this.weibullThreeParProbabilityPlot(); + } + + // Check data for suffient points + this.weibullStandardNumberOfParameters = 1; + if(this.numberOfDataPoints<3)throw new IllegalArgumentException("There must be at least three data points - preferably considerably more"); + + // Create instance of Regression + Regression min = new Regression(this.sortedData, this.sortedData); + + // Calculate initial estimates + double[] start = new double[1]; + start[0] = 4.0; + double[] step = {Math.abs(0.3*start[0])}; + this.initialEstimates = start; + double tolerance = 1e-10; + + // Add constraint; gamma>0 + min.addConstraint(0, -1, 0); + + // Create an instance of WeibullStandardProbPlotFunc + WeibullStandardProbPlotFunc wppf = new WeibullStandardProbPlotFunc(); + wppf.setDataArray(this.numberOfDataPoints); + + // Obtain best probability plot varying gamma + // by minimizing the sum of squares of the differences between the ordered data and the ordered statistic medians + min.simplex(wppf, start.clone(), step, tolerance); + + // Obtain best estimates or first minimisation + double[] firstBests = min.getBestEstimates(); + + // Get mu and sigma value errors + double[] firstErrors = min.getBestEstimatesErrors(); + + // Get sum of squares + double ss = min.getSumOfSquares(); + + //Calculate new initial estimates + double[] start2 = new double[this.weibullStandardNumberOfParameters]; + start2[0] = 2.0*firstBests[0] - start[0]; + if(start2[0]>minimum)start2[0] = minimum*(1.0 - Math.abs(minimum)*0.05); + step[0] = Math.abs(start2[0]*0.1); + if(step[0]==0)step[0] = this.range*0.01; + + min.simplex(wppf, start2.clone(), step, tolerance); + + // Get gamma for best correlation coefficient + this.weibullStandardParam = min.getBestEstimates(); + + // Get gamma value errors + this.weibullStandardParamErrors = min.getBestEstimatesErrors(); + + // Get sum of squares + this.weibullStandardSumOfSquares = min.getSumOfSquares(); + + // Calculate Weibull Standard order statistic medians + this.weibullStandardOrderMedians = Stat.weibullOrderStatisticMedians(this.weibullStandardParam[0], this.numberOfDataPoints); + + // Regression of the ordered data on the Weibull order statistic medians + Regression reg = new Regression(this.weibullStandardOrderMedians, this.sortedData); + reg.linear(); + + // Intercept and gradient of best fit straight line + this.weibullStandardLine = reg.getBestEstimates(); + + // Estimated erors of the intercept and gradient of best fit straight line + this.weibullStandardLineErrors = reg.getBestEstimatesErrors(); + + // Correlation coefficient + this.weibullStandardCorrCoeff = reg.getSampleR(); + + // Initialize data arrays for plotting + double[][] data = PlotGraph.data(2,this.numberOfDataPoints); + + // Assign data to plotting arrays + data[0] = this.weibullStandardOrderMedians; + data[1] = this.sortedData; + + data[2] = weibullStandardOrderMedians; + for(int i=0; i<this.numberOfDataPoints; i++){ + data[3][i] = this.weibullStandardLine[0] + this.weibullStandardLine[1]*weibullStandardOrderMedians[i]; + } + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("Weibull Order Statistic Medians"); + pg.setYaxisLegend("Ordered Data Values"); + pg.setGraphTitle("Standard Weibull probability plot: gradient = " + Fmath.truncate(this.weibullStandardLine[1], 4) + ", intercept = " + Fmath.truncate(this.weibullStandardLine[0], 4) + ", R = " + Fmath.truncate(this.weibullStandardCorrCoeff, 4)); + pg.setGraphTitle2(" mu = 0, sigma = 1, gamma = " + Fmath.truncate(this.weibullStandardParam[0], 4)); + + // Plot + pg.plot(); + + this.weibullStandardDone = true; + this.probPlotDone = true; + } + + // WEIBULL PROBABILITY PLOT + // Standard (one parameter) (mu = 0, sigma =1) + public void weibullOneParProbabilityPlot(){ + this.weibullStandardProbabilityPlot(); + } + + // Return Standard Weibull gamma + public double weibullStandardGamma(){ + if(!this.weibullStandardDone)throw new IllegalArgumentException("Standard Weibull Probability Plot method has not been called"); + return this.weibullStandardParam[0]; + } + + // Return Standard Weibull gamma error + public double weibullStandardGammaError(){ + if(!this.weibullStandardDone)throw new IllegalArgumentException("Standard Weibull Probability Plot method has not been called"); + return this.weibullStandardParamErrors[0]; + } + + // Return Standard Weibull order statistic medians + public double[] weibullStandardOrderStatisticMedians(){ + if(!this.weibullStandardDone)throw new IllegalArgumentException("Standard Weibull Probability Plot method has not been called"); + return this.weibullStandardOrderMedians; + } + + // Return the Standard Weibull gradient + public double weibullStandardGradient(){ + if(!this.weibullStandardDone)throw new IllegalArgumentException("Standard Weibull Probability Plot method has not been called"); + return this.weibullStandardLine[1]; + } + + // Return the error of the Standard Weibull gradient + public double weibullStandardGradientError(){ + if(!this.weibullStandardDone)throw new IllegalArgumentException("Standard Weibull Probability Plot method has not been called"); + return this.weibullStandardLineErrors[1]; + } + + // Return the Standard Weibull intercept + public double weibullStandardIntercept(){ + if(!this.weibullStandardDone)throw new IllegalArgumentException("Standard Weibull Probability Plot method has not been called"); + return this.weibullStandardLine[0]; + } + + // Return the error of the Standard Weibull intercept + public double weibullStandardInterceptError(){ + if(!this.weibullStandardDone)throw new IllegalArgumentException("Standard Weibull Probability Plot method has not been called"); + return this.weibullStandardLineErrors[0]; + } + + // Return the Standard Weibull correlation coefficient + public double weibullStandardCorrelationCoefficient(){ + if(!this.weibullStandardDone)throw new IllegalArgumentException("Standard Weibull Probability Plot method has not been called"); + return this.weibullStandardCorrCoeff; + } + + // Return the sum of squares at the Standard Weibull minimum + public double weibullStandardSumOfSquares(){ + if(!this.weibullStandardDone)throw new IllegalArgumentException("Standard Weibull Probability Plot method has not been called"); + return this.weibullStandardSumOfSquares; + } + + + // EXPONENTIAL PROBABILITY PLOT + public void exponentialProbabilityPlot(){ + this.lastMethod = 2; + + // Check for suffient data points + this.exponentialNumberOfParameters = 2; + if(this.numberOfDataPoints<3)throw new IllegalArgumentException("There must be at least three data points - preferably considerably more"); + + // Create instance of Regression + Regression min = new Regression(this.sortedData, this.sortedData); + double muest = minimum; + if(muest==0.0)muest = this.standardDeviation/3.0; + double sigmaest = this.standardDeviation; + double[] start = {muest, sigmaest}; + this.initialEstimates = start; + double[] step = {0.3*muest, 0.3*sigmaest}; + double tolerance = 1e-10; + + // Add constraint; sigma>0 + min.addConstraint(1, -1, 0); + + // Create an instance of ExponentialProbPlotFunc + ExponentialProbPlotFunc eppf = new ExponentialProbPlotFunc(); + eppf.setDataArray(this.numberOfDataPoints); + + // Obtain best probability plot varying mu and sigma + // by minimizing the sum of squares of the differences between the ordered data and the ordered statistic medians + min.simplex(eppf, start, step, tolerance); + + // Get mu and sigma values + this.exponentialParam = min.getBestEstimates(); + + // Get mu and sigma value errors + this.exponentialParamErrors = min.getBestEstimatesErrors(); + + // Get sum of squares + this.exponentialSumOfSquares = min.getSumOfSquares(); + + // Calculate Exponential order statistic medians (Weibull with gamma = 1) + this.exponentialOrderMedians = Stat.weibullOrderStatisticMedians(this.exponentialParam[0], this.exponentialParam[1], 1.0, this.numberOfDataPoints); + + // Regression of the ordered data on the Exponential order statistic medians + Regression reg = new Regression(this.exponentialOrderMedians, this.sortedData); + reg.linear(); + + // Intercept and gradient of best fit straight line + this.exponentialLine = reg.getBestEstimates(); + + // Estimated erors of the intercept and gradient of best fit straight line + this.exponentialLineErrors = reg.getBestEstimatesErrors(); + + // Correlation coefficient + this.exponentialCorrCoeff = reg.getSampleR(); + + // Initialize data arrays for plotting + double[][] data = PlotGraph.data(2,this.numberOfDataPoints); + + // Assign data to plotting arrays + data[0] = this.exponentialOrderMedians; + data[1] = this.sortedData; + + data[2] = exponentialOrderMedians; + for(int i=0; i<this.numberOfDataPoints; i++){ + data[3][i] = this.exponentialLine[0] + this.exponentialLine[1]*exponentialOrderMedians[i]; + } + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("Exponential Order Statistic Medians"); + pg.setYaxisLegend("Ordered Data Values"); + pg.setGraphTitle("Exponential probability plot: gradient = " + Fmath.truncate(this.exponentialLine[1], 4) + ", intercept = " + Fmath.truncate(this.exponentialLine[0], 4) + ", R = " + Fmath.truncate(this.exponentialCorrCoeff, 4)); + pg.setGraphTitle2(" mu = " + Fmath.truncate(this.exponentialParam[0], 4) + ", sigma = " + Fmath.truncate(this.exponentialParam[1], 4)); + + // Plot + pg.plot(); + + this.exponentialDone = true; + this.probPlotDone = true; + } + + // Return Exponential mu + public double exponentialMu(){ + if(!this.exponentialDone)throw new IllegalArgumentException("Exponential Probability Plot method has not been called"); + return this.exponentialParam[0]; + } + + // Return Exponential mu error + public double exponentialMuError(){ + if(!this.exponentialDone)throw new IllegalArgumentException("Exponential Probability Plot method has not been called"); + return this.exponentialParamErrors[0]; + } + + // Return Exponential sigma + public double exponentialSigma(){ + if(!this.exponentialDone)throw new IllegalArgumentException("Exponential Probability Plot method has not been called"); + return this.exponentialParam[1]; + } + + // Return Exponential sigma error + public double exponentialSigmaError(){ + if(!this.exponentialDone)throw new IllegalArgumentException("Exponential Probability Plot method has not been called"); + return this.exponentialParamErrors[1]; + } + + + // Return Exponential order statistic medians + public double[] exponentialOrderStatisticMedians(){ + if(!this.exponentialDone)throw new IllegalArgumentException("Exponential Probability Plot method has not been called"); + return this.exponentialOrderMedians; + } + + // Return the Exponential gradient + public double exponentialGradient(){ + if(!this.exponentialDone)throw new IllegalArgumentException("Exponential Probability Plot method has not been called"); + return this.exponentialLine[1]; + } + + // Return the error of the Exponential gradient + public double exponentialGradientError(){ + if(!this.exponentialDone)throw new IllegalArgumentException("Exponential Probability Plot method has not been called"); + return this.exponentialLineErrors[1]; + } + + // Return the Exponential intercept + public double exponentialIntercept(){ + if(!this.exponentialDone)throw new IllegalArgumentException("Exponential Probability Plot method has not been called"); + return this.exponentialLine[0]; + } + + // Return the error of the Exponential intercept + public double exponentialInterceptError(){ + if(!this.exponentialDone)throw new IllegalArgumentException("Exponential Probability Plot method has not been called"); + return this.exponentialLineErrors[0]; + } + + // Return the Exponential correlation coefficient + public double exponentialCorrelationCoefficient(){ + if(!this.exponentialDone)throw new IllegalArgumentException("Exponential Probability Plot method has not been called"); + return this.exponentialCorrCoeff; + } + + // Return the sum of squares at the Exponential minimum + public double exponentialSumOfSquares(){ + if(!this.exponentialDone)throw new IllegalArgumentException("Exponential Probability Plot method has not been called"); + return this.exponentialSumOfSquares; + } + + + // FRECHET PROBABILITY PLOT + public void frechetProbabilityPlot(){ + this.lastMethod = 7; + + // Check for suffient data points + this.frechetNumberOfParameters = 3; + if(this.numberOfDataPoints<4)throw new IllegalArgumentException("There must be at least four data points - preferably considerably more"); + + // Create instance of Regression + Regression min = new Regression(this.sortedData, this.sortedData); + + // Calculate initial estimates + double[] start = new double[3]; + start[0] = this.minimum - 0.1*Math.abs(this.minimum); + start[1] = this.peakWidth()/3.0; + if(start[1]<1.0)start[1] = 2.0; + start[2] = 4.0; + this.initialEstimates = start; + double[] step = {Math.abs(0.3*start[0]), Math.abs(0.3*start[1]), Math.abs(0.3*start[2])}; + if(step[0]==0)step[0] = this.range*0.01; + double tolerance = 1e-10; + + // Add constraint; mu<minimum, sigma>0, gamma>0 + min.addConstraint(0, +1, minimum); + min.addConstraint(1, -1, 0); + min.addConstraint(2, -1, 0); + + // Create an instance of FrechetProbPlotFunc + FrechetProbPlotFunc fppf = new FrechetProbPlotFunc(); + fppf.setDataArray(this.numberOfDataPoints); + + // Obtain best probability plot varying mu, sigma and gamma + // by minimizing the sum of squares of the differences between the ordered data and the ordered statistic medians + min.simplex(fppf, start.clone(), step, tolerance); + + // Obtain best estimates or first minimisation + double[] firstBests = min.getBestEstimates(); + + double ss = min.getSumOfSquares(); + + //Calculate new initial estimates + double[] start2 = new double[this.frechetNumberOfParameters]; + start2[0] = 2.0*firstBests[0] - start[0]; + if(start2[0]>minimum)start2[0] = minimum*(1.0 - Math.abs(minimum)*0.05); + step[0] = Math.abs(start2[0]*0.1); + if(step[0]==0)step[0] = this.range*0.01; + start2[1] = 2.0*firstBests[1] - start[1]; + if(start2[1]<=0.0)start2[1] = Math.abs(2.0*firstBests[1] - 0.98*start[1]); + step[1] = Math.abs(start2[1]*0.1); + start2[2] = 2.0*firstBests[2] - start[2]; + if(start2[1]<=0.0)start2[2] = Math.abs(2.0*firstBests[2] - 0.98*start[2]); + step[2] = Math.abs(start2[2]*0.1); + + min.simplex(fppf, start2.clone(), step, tolerance); + + // Get mu, sigma and gamma for best correlation coefficient + this.frechetParam = min.getBestEstimates(); + double ss2 = min.getSumOfSquares(); + if(ss<ss2)this.frechetParam = firstBests; + + // Calculate Frechet order statistic medians + this.frechetOrderMedians = Stat.frechetOrderStatisticMedians(this.frechetParam[0], this.frechetParam[1], this.frechetParam[2], this.numberOfDataPoints); + + // Regression of the ordered data on the Frechet order statistic medians + Regression reg = new Regression(this.frechetOrderMedians, this.sortedData); + reg.linear(); + + // Intercept and gradient of best fit straight line + this.frechetLine = reg.getBestEstimates(); + + // Estimated erors of the intercept and gradient of best fit straight line + this.frechetLineErrors = reg.getBestEstimatesErrors(); + + // Correlation coefficient + this.frechetCorrCoeff = reg.getSampleR(); + + // Initialize data arrays for plotting + double[][] data = PlotGraph.data(2,this.numberOfDataPoints); + + // Assign data to plotting arrays + data[0] = this.frechetOrderMedians; + data[1] = this.sortedData; + + data[2] = frechetOrderMedians; + for(int i=0; i<this.numberOfDataPoints; i++){ + data[3][i] = this.frechetLine[0] + this.frechetLine[1]*frechetOrderMedians[i]; + } + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("Frechet Order Statistic Medians"); + pg.setYaxisLegend("Ordered Data Values"); + pg.setGraphTitle("Frechet probability plot: gradient = " + Fmath.truncate(this.frechetLine[1], 4) + ", intercept = " + Fmath.truncate(this.frechetLine[0], 4) + ", R = " + Fmath.truncate(this.frechetCorrCoeff, 4)); + pg.setGraphTitle2(" mu = " + Fmath.truncate(this.frechetParam[0], 4) + ", sigma = " + Fmath.truncate(this.frechetParam[1], 4) + ", gamma = " + Fmath.truncate(this.frechetParam[2], 4)); + + // Plot + pg.plot(); + + this.frechetDone = true; + this.probPlotDone = true; + } + + // Return Frechet mu + public double frechetMu(){ + if(!this.frechetDone)throw new IllegalArgumentException("Frechet Probability Plot method has not been called"); + return this.frechetParam[0]; + } + + // Return Frechet mu error + public double frechetMuError(){ + if(!this.frechetDone)throw new IllegalArgumentException("Frechet Probability Plot method has not been called"); + return this.frechetParamErrors[0]; + } + + // Return Frechet sigma + public double frechetSigma(){ + if(!this.frechetDone)throw new IllegalArgumentException("Frechet Probability Plot method has not been called"); + return this.frechetParam[1]; + } + + // Return Frechet sigma error + public double frechetSigmaError(){ + if(!this.frechetDone)throw new IllegalArgumentException("Frechet Probability Plot method has not been called"); + return this.frechetParamErrors[1]; + } + + // Return Frechet gamma + public double frechetGamma(){ + if(!this.frechetDone)throw new IllegalArgumentException("Frechet Probability Plot method has not been called"); + return this.frechetParam[2]; + } + + // Return Frechet gamma error + public double frechetGammaError(){ + if(!this.frechetDone)throw new IllegalArgumentException("Frechet Probability Plot method has not been called"); + return this.frechetParamErrors[2]; + } + + // Return Frechet order statistic medians + public double[] frechetOrderStatisticMedians(){ + if(!this.frechetDone)throw new IllegalArgumentException("Frechet Probability Plot method has not been called"); + return this.frechetOrderMedians; + } + + // Return the Frechet gradient + public double frechetGradient(){ + if(!this.frechetDone)throw new IllegalArgumentException("Frechet Probability Plot method has not been called"); + return this.frechetLine[1]; + } + + // Return the error of the Frechet gradient + public double frechetGradientError(){ + if(!this.frechetDone)throw new IllegalArgumentException("Frechet Probability Plot method has not been called"); + return this.frechetLineErrors[1]; + } + + // Return the Frechet intercept + public double frechetIntercept(){ + if(!this.frechetDone)throw new IllegalArgumentException("Frechet Probability Plot method has not been called"); + return this.frechetLine[0]; + } + + // Return the error of the Frechet intercept + public double frechetInterceptError(){ + if(!this.frechetDone)throw new IllegalArgumentException("Frechet Probability Plot method has not been called"); + return this.frechetLineErrors[0]; + } + + // Return the Frechet correlation coefficient + public double frechetCorrelationCoefficient(){ + if(!this.frechetDone)throw new IllegalArgumentException("Frechet Probability Plot method has not been called"); + return this.frechetCorrCoeff; + } + + // Return the sum of squares at the Frechet minimum + public double frechetSumOfSquares(){ + if(!this.frechetDone)throw new IllegalArgumentException("Frechet Probability Plot method has not been called"); + return this.frechetSumOfSquares; + } + + + + // GUMBEL (MINIMUM ORDER STATISTIC) PROBABILITY PLOT + public void gumbelMinProbabilityPlot(){ + this.lastMethod = 5; + + // Check for suffient data points + this.gumbelMinNumberOfParameters = 2; + if(this.numberOfDataPoints<3)throw new IllegalArgumentException("There must be at least three data points - preferably considerably more"); + + // Create instance of Regression + Regression min = new Regression(this.sortedData, this.sortedData); + double muest = mean; + if(muest==0.0)muest = this.standardDeviation/3.0; + double sigmaest = this.standardDeviation; + double[] start = {muest, sigmaest}; + double[] step = {0.3*muest, 0.3*sigmaest}; + this.initialEstimates = start; + double tolerance = 1e-10; + + // Add constraint; sigma>0 + min.addConstraint(1, -1, 0); + + // Create an instance of Gumbel (minimum order statistic)ProbPlotFunc + GumbelMinProbPlotFunc gmippf = new GumbelMinProbPlotFunc(); + gmippf.setDataArray(this.numberOfDataPoints); + + // Obtain best probability plot varying mu and sigma + // by minimizing the sum of squares of the differences between the ordered data and the ordered statistic medians + min.simplex(gmippf, start, step, tolerance); + + // Get mu and sigma values + this.gumbelMinParam = min.getBestEstimates(); + + // Get mu and sigma value errors + this.gumbelMinParamErrors = min.getBestEstimatesErrors(); + + // Get sum of squares + this.gumbelMinSumOfSquares = min.getSumOfSquares(); + + // Calculate Gumbel (minimum order statistic) order statistic medians + this.gumbelMinOrderMedians = Stat.gumbelMinOrderStatisticMedians(this.gumbelMinParam[0], this.gumbelMinParam[1], this.numberOfDataPoints); + + // Regression of the ordered data on the Gumbel (minimum order statistic) order statistic medians + Regression reg = new Regression(this.gumbelMinOrderMedians, this.sortedData); + reg.linear(); + + // Intercept and gradient of best fit straight line + this.gumbelMinLine = reg.getBestEstimates(); + + // Estimated erors of the intercept and gradient of best fit straight line + this.gumbelMinLineErrors = reg.getBestEstimatesErrors(); + + // Correlation coefficient + this.gumbelMinCorrCoeff = reg.getSampleR(); + + // Initialize data arrays for plotting + double[][] data = PlotGraph.data(2,this.numberOfDataPoints); + + // Assign data to plotting arrays + data[0] = this.gumbelMinOrderMedians; + data[1] = this.sortedData; + + data[2] = gumbelMinOrderMedians; + for(int i=0; i<this.numberOfDataPoints; i++){ + data[3][i] = this.gumbelMinLine[0] + this.gumbelMinLine[1]*gumbelMinOrderMedians[i]; + } + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("Gumbel (minimum order statistic) Order Statistic Medians"); + pg.setYaxisLegend("Ordered Data Values"); + pg.setGraphTitle("Gumbel (minimum order statistic) probability plot: gradient = " + Fmath.truncate(this.gumbelMinLine[1], 4) + ", intercept = " + Fmath.truncate(this.gumbelMinLine[0], 4) + ", R = " + Fmath.truncate(this.gumbelMinCorrCoeff, 4)); + pg.setGraphTitle2(" mu = " + Fmath.truncate(this.gumbelMinParam[0], 4) + ", sigma = " + Fmath.truncate(this.gumbelMinParam[1], 4)); + + // Plot + pg.plot(); + + this.gumbelMinDone = true; + this.probPlotDone = true; + } + + // Return Gumbel (minimum order statistic) mu + public double gumbelMinMu(){ + if(!this.gumbelMinDone)throw new IllegalArgumentException("Gumbel (minimum order statistic) Probability Plot method has not been called"); + return this.gumbelMinParam[0]; + } + + // Return Gumbel (minimum order statistic) mu error + public double gumbelMinMuError(){ + if(!this.gumbelMinDone)throw new IllegalArgumentException("Gumbel (minimum order statistic) Probability Plot method has not been called"); + return this.gumbelMinParamErrors[0]; + } + + // Return Gumbel (minimum order statistic) sigma + public double gumbelMinSigma(){ + if(!this.gumbelMinDone)throw new IllegalArgumentException("Gumbel (minimum order statistic) Probability Plot method has not been called"); + return this.gumbelMinParam[1]; + } + + // Return Gumbel (minimum order statistic) sigma error + public double gumbelMinSigmaError(){ + if(!this.gumbelMinDone)throw new IllegalArgumentException("Gumbel (minimum order statistic) Probability Plot method has not been called"); + return this.gumbelMinParamErrors[1]; + } + + // Return Gumbel (minimum order statistic) order statistic medians + public double[] gumbelMinOrderStatisticMedians(){ + if(!this.gumbelMinDone)throw new IllegalArgumentException("Gumbel (minimum order statistic) Probability Plot method has not been called"); + return this.gumbelMinOrderMedians; + } + + // Return the Gumbel (minimum order statistic) gradient + public double gumbelMinGradient(){ + if(!this.gumbelMinDone)throw new IllegalArgumentException("Gumbel (minimum order statistic) Probability Plot method has not been called"); + return this.gumbelMinLine[1]; + } + + // Return the error of the Gumbel (minimum order statistic) gradient + public double gumbelMinGradientError(){ + if(!this.gumbelMinDone)throw new IllegalArgumentException("Gumbel (minimum order statistic) Probability Plot method has not been called"); + return this.gumbelMinLineErrors[1]; + } + + // Return the Gumbel (minimum order statistic) intercept + public double gumbelMinIntercept(){ + if(!this.gumbelMinDone)throw new IllegalArgumentException("Gumbel (minimum order statistic) Probability Plot method has not been called"); + return this.gumbelMinLine[0]; + } + + // Return the error of the Gumbel (minimum order statistic) intercept + public double gumbelMinInterceptError(){ + if(!this.gumbelMinDone)throw new IllegalArgumentException("Gumbel (minimum order statistic) Probability Plot method has not been called"); + return this.gumbelMinLineErrors[0]; + } + + // Return the Gumbel (minimum order statistic) correlation coefficient + public double gumbelMinCorrelationCoefficient(){ + if(!this.gumbelMinDone)throw new IllegalArgumentException("Gumbel (minimum order statistic) Probability Plot method has not been called"); + return this.gumbelMinCorrCoeff; + } + + // Return the sum of squares at the Gumbel (minimum order statistic) minimum + public double gumbelMinSumOfSquares(){ + if(!this.gumbelMinDone)throw new IllegalArgumentException("Gumbel (minimum order statistic) Probability Plot method has not been called"); + return this.gumbelMinSumOfSquares; + } + + + // GUMBEL (MAXIMUM ORDER STATISTIC) PROBABILITY PLOT + public void gumbelMaxProbabilityPlot(){ + this.lastMethod = 6; + + // Check for suffient data points + this.gumbelMaxNumberOfParameters = 2; + if(this.numberOfDataPoints<3)throw new IllegalArgumentException("There must be at least three data points - preferably considerably more"); + + // Create instance of Regression + Regression min = new Regression(this.sortedData, this.sortedData); + double muest = mean; + if(muest==0.0)muest = this.standardDeviation/3.0; + double sigmaest = this.standardDeviation; + double[] start = {muest, sigmaest}; + this.initialEstimates = start; + double[] step = {0.3*muest, 0.3*sigmaest}; + double tolerance = 1e-10; + + // Add constraint; sigma>0 + min.addConstraint(1, -1, 0); + + // Create an instance of Gumbel (maximum order statistic)ProbPlotFunc + GumbelMaxProbPlotFunc gmappf = new GumbelMaxProbPlotFunc(); + gmappf.setDataArray(this.numberOfDataPoints); + + // Obtain best probability plot varying mu and sigma + // by minimizing the sum of squares of the differences between the ordered data and the ordered statistic medians + min.simplex(gmappf, start, step, tolerance); + + // Get mu and sigma values + this.gumbelMaxParam = min.getBestEstimates(); + + // Get mu and sigma value errors + this.gumbelMaxParamErrors = min.getBestEstimatesErrors(); + + // Get sum of squares + this.gumbelMaxSumOfSquares = min.getSumOfSquares(); + + // Calculate Gumbel (maximum order statistic) order statistic medians + this.gumbelMaxOrderMedians = Stat.gumbelMaxOrderStatisticMedians(this.gumbelMaxParam[0], this.gumbelMaxParam[1], this.numberOfDataPoints); + + // Regression of the ordered data on the Gumbel (maximum order statistic) order statistic medians + Regression reg = new Regression(this.gumbelMaxOrderMedians, this.sortedData); + reg.linear(); + + // Intercept and gradient of best fit straight line + this.gumbelMaxLine = reg.getBestEstimates(); + + // Correlation coefficient + this.gumbelMaxCorrCoeff = reg.getSampleR(); + + // Initialize data arrays for plotting + double[][] data = PlotGraph.data(2,this.numberOfDataPoints); + + // Assign data to plotting arrays + data[0] = this.gumbelMaxOrderMedians; + data[1] = this.sortedData; + + data[2] = gumbelMaxOrderMedians; + for(int i=0; i<this.numberOfDataPoints; i++){ + data[3][i] = this.gumbelMaxLine[0] + this.gumbelMaxLine[1]*gumbelMaxOrderMedians[i]; + } + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("Gumbel (maximum order statistic) Order Statistic Medians"); + pg.setYaxisLegend("Ordered Data Values"); + pg.setGraphTitle("Gumbel (maximum order statistic) probability plot: gradient = " + Fmath.truncate(this.gumbelMaxLine[1], 4) + ", intercept = " + Fmath.truncate(this.gumbelMaxLine[0], 4) + ", R = " + Fmath.truncate(this.gumbelMaxCorrCoeff, 4)); + pg.setGraphTitle2(" mu = " + Fmath.truncate(this.gumbelMaxParam[0], 4) + ", sigma = " + Fmath.truncate(this.gumbelMaxParam[1], 4)); + + // Plot + pg.plot(); + + this.gumbelMaxDone = true; + this.probPlotDone = true; + } + + // Return Gumbel (maximum order statistic) mu + public double gumbelMaxMu(){ + if(!this.gumbelMaxDone)throw new IllegalArgumentException("Gumbel (maximum order statistic) Probability Plot method has not been called"); + return this.gumbelMaxParam[0]; + } + + // Return Gumbel (maximum order statistic) mu error + public double gumbelMaxMuError(){ + if(!this.gumbelMaxDone)throw new IllegalArgumentException("Gumbel (maximum order statistic) Probability Plot method has not been called"); + return this.gumbelMaxParamErrors[0]; + } + + // Return Gumbel (maximum order statistic) sigma + public double gumbelMaxSigma(){ + if(!this.gumbelMaxDone)throw new IllegalArgumentException("Gumbel (maximum order statistic) Probability Plot method has not been called"); + return this.gumbelMaxParam[1]; + } + + // Return Gumbel (maximum order statistic) sigma error + public double gumbelMaxSigmaError(){ + if(!this.gumbelMaxDone)throw new IllegalArgumentException("Gumbel (maximum order statistic) Probability Plot method has not been called"); + return this.gumbelMaxParamErrors[1]; + } + + // Return Gumbel (maximum order statistic) order statistic medians + public double[] gumbelMaxOrderStatisticMedians(){ + if(!this.gumbelMaxDone)throw new IllegalArgumentException("Gumbel (maximum order statistic) Probability Plot method has not been called"); + return this.gumbelMaxOrderMedians; + } + + // Return the Gumbel (maximum order statistic) gradient + public double gumbelMaxGradient(){ + if(!this.gumbelMaxDone)throw new IllegalArgumentException("Gumbel (maximum order statistic) Probability Plot method has not been called"); + return this.gumbelMaxLine[1]; + } + + // Return the error of the Gumbel (maximum order statistic) gradient + public double gumbelMaxGradientError(){ + if(!this.gumbelMaxDone)throw new IllegalArgumentException("Gumbel (maximum order statistic) Probability Plot method has not been called"); + return this.gumbelMaxLineErrors[1]; + } + + // Return the Gumbel (maximum order statistic) intercept + public double gumbelMaxIntercept(){ + if(!this.gumbelMaxDone)throw new IllegalArgumentException("Gumbel (maximum order statistic) Probability Plot method has not been called"); + return this.gumbelMaxLine[0]; + } + + // Return the error of the Gumbel (maximum order statistic) intercept + public double gumbelMaxInterceptError(){ + if(!this.gumbelMaxDone)throw new IllegalArgumentException("Gumbel (maximum order statistic) Probability Plot method has not been called"); + return this.gumbelMaxLineErrors[0]; + } + + // Return the Gumbel (maximum order statistic) correlation coefficient + public double gumbelMaxCorrelationCoefficient(){ + if(!this.gumbelMaxDone)throw new IllegalArgumentException("Gumbel (maximum order statistic) Probability Plot method has not been called"); + return this.gumbelMaxCorrCoeff; + } + + // Return the sum of squares at the Gumbel (maximum order statistic) minimum + public double gumbelMaxSumOfSquares(){ + if(!this.gumbelMaxDone)throw new IllegalArgumentException("Gumbel (maximum order statistic) Probability Plot method has not been called"); + return this.gumbelMaxSumOfSquares; + } + + + // RAYLEIGH PROBABILITY PLOT + public void rayleighProbabilityPlot(){ + this.lastMethod = 3; + + // Check for suffient data points + this.rayleighNumberOfParameters = 1; + if(this.numberOfDataPoints<3)throw new IllegalArgumentException("There must be at least three data points - preferably considerably more"); + + // Create instance of Regression + Regression min = new Regression(this.sortedData, this.sortedData); + double sigmaest = this.standardDeviation; + double[] start = {sigmaest}; + double[] step = {0.3*sigmaest}; + this.initialEstimates = start; + double tolerance = 1e-10; + + // Add constraint; beta>0 + min.addConstraint(0, -1, 0); + + // Create an instance of RayleighProbPlotFunc + RayleighProbPlotFunc rppf = new RayleighProbPlotFunc(); + rppf.setDataArray(this.numberOfDataPoints); + + // Obtain best probability plot varying beta + // by minimizing the sum of squares of the differences between the ordered data and the ordered statistic medians + min.simplex(rppf, start, step, tolerance); + + // Get mu and sigma values + this.rayleighParam = min.getBestEstimates(); + + // Get mu and sigma value errors + this.rayleighParamErrors = min.getBestEstimatesErrors(); + + // Get sum of squares + this.rayleighSumOfSquares = min.getSumOfSquares(); + + // Calculate Rayleigh order statistic medians (Weibull with mu = 0, sigma = sqrt(2).beta, gamma = 2) + this.rayleighOrderMedians = Stat.weibullOrderStatisticMedians(0.0, this.rayleighParam[0]*Math.sqrt(2.0), 2.0, this.numberOfDataPoints); + + // Regression of the ordered data on the Rayleigh order statistic medians + Regression reg = new Regression(this.rayleighOrderMedians, this.sortedData); + reg.linear(); + + // Intercept and gradient of best fit straight line + this.rayleighLine = reg.getBestEstimates(); + + // Estimated erors of the intercept and gradient of best fit straight line + this.rayleighLineErrors = reg.getBestEstimatesErrors(); + + // Correlation coefficient + this.rayleighCorrCoeff = reg.getSampleR(); + + // Initialize data arrays for plotting + double[][] data = PlotGraph.data(2,this.numberOfDataPoints); + + // Assign data to plotting arrays + data[0] = this.rayleighOrderMedians; + data[1] = this.sortedData; + + data[2] = rayleighOrderMedians; + for(int i=0; i<this.numberOfDataPoints; i++){ + data[3][i] = this.rayleighLine[0] + this.rayleighLine[1]*rayleighOrderMedians[i]; + } + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("Rayleigh Order Statistic Medians"); + pg.setYaxisLegend("Ordered Data Values"); + pg.setGraphTitle("Rayleigh probability plot: gradient = " + Fmath.truncate(this.rayleighLine[1], 4) + ", intercept = " + Fmath.truncate(this.rayleighLine[0], 4) + ", R = " + Fmath.truncate(this.rayleighCorrCoeff, 4)); + pg.setGraphTitle2(" beta = " + Fmath.truncate(this.rayleighParam[0], 4)); + + // Plot + pg.plot(); + + this.rayleighDone = true; + this.probPlotDone = true; + } + + // Return Rayleigh beta + public double rayleighBeta(){ + if(!this.rayleighDone)throw new IllegalArgumentException("Rayleigh Probability Plot method has not been called"); + return this.rayleighParam[0]; + } + + // Return Rayleigh beta error + public double rayleighBetaError(){ + if(!this.rayleighDone)throw new IllegalArgumentException("Rayleigh Probability Plot method has not been called"); + return this.rayleighParamErrors[0]; + } + + // Return Rayleigh order statistic medians + public double[] rayleighOrderStatisticMedians(){ + if(!this.rayleighDone)throw new IllegalArgumentException("Rayleigh Probability Plot method has not been called"); + return this.rayleighOrderMedians; + } + + // Return the Rayleigh gradient + public double rayleighGradient(){ + if(!this.rayleighDone)throw new IllegalArgumentException("Rayleigh Probability Plot method has not been called"); + return this.rayleighLine[1]; + } + + // Return the error of the Rayleigh gradient + public double rayleighGradientError(){ + if(!this.rayleighDone)throw new IllegalArgumentException("Rayleigh Probability Plot method has not been called"); + return this.rayleighLineErrors[1]; + } + + // Return the Rayleigh intercept + public double rayleighIntercept(){ + if(!this.rayleighDone)throw new IllegalArgumentException("Rayleigh Probability Plot method has not been called"); + return this.rayleighLine[0]; + } + + // Return the error of the Rayleigh intercept + public double rayleighInterceptError(){ + if(!this.rayleighDone)throw new IllegalArgumentException("Rayleigh Probability Plot method has not been called"); + return this.rayleighLineErrors[0]; + } + + // Return the Rayleigh correlation coefficient + public double rayleighCorrelationCoefficient(){ + if(!this.rayleighDone)throw new IllegalArgumentException("Rayleigh Probability Plot method has not been called"); + return this.rayleighCorrCoeff; + } + + // Return the sum of squares at the Rayleigh minimum + public double rayleighSumOfSquares(){ + if(!this.rayleighDone)throw new IllegalArgumentException("Rayleigh Probability Plot method has not been called"); + return this.rayleighSumOfSquares; + } + + // PARETO PROBABILITY PLOT + public void paretoProbabilityPlot(){ + this.lastMethod = 4; + + // Check for suffient data points + this.paretoNumberOfParameters = 2; + if(this.numberOfDataPoints<3)throw new IllegalArgumentException("There must be at least three data points - preferably considerably more"); + + // Create instance of Regression + Regression min = new Regression(this.sortedData, this.sortedData); + double betaest = this.minimum; + double alphaest = this.mean/(this.mean - betaest); + double[] start = {alphaest, betaest}; + double[] step = {0.3*alphaest, 0.3*betaest}; + this.initialEstimates = start; + double tolerance = 1e-10; + + // Create an instance of ParetoProbPlotFunc + ParetoProbPlotFunc pppf = new ParetoProbPlotFunc(); + pppf.setDataArray(this.numberOfDataPoints); + + // Obtain best probability plot varying alpha and beta + // by minimizing the sum of squares of the differences between the ordered data and the ordered statistic medians + min.simplex(pppf, start, step, tolerance); + + // Get alpha and beta values + this.paretoParam = min.getBestEstimates(); + + // Get alpha and beta value errors + this.paretoParamErrors = min.getBestEstimatesErrors(); + + // Get sum of squares + this.paretoSumOfSquares = min.getSumOfSquares(); + + // Calculate Pareto order statistic medians + this.paretoOrderMedians = Stat.paretoOrderStatisticMedians(this.paretoParam[0], this.paretoParam[1], this.numberOfDataPoints); + + // Regression of the ordered data on the Pareto order statistic medians + Regression reg = new Regression(this.paretoOrderMedians, this.sortedData); + reg.linear(); + + // Intercept and gradient of best fit straight line + this.paretoLine = reg.getBestEstimates(); + + // Estimated erors of the intercept and gradient of best fit straight line + this.paretoLineErrors = reg.getBestEstimatesErrors(); + + // Correlation coefficient + this.paretoCorrCoeff = reg.getSampleR(); + + // Initialize data arrays for plotting + double[][] data = PlotGraph.data(2,this.numberOfDataPoints); + + // Assign data to plotting arrays + data[0] = this.paretoOrderMedians; + data[1] = this.sortedData; + + data[2] = paretoOrderMedians; + for(int i=0; i<this.numberOfDataPoints; i++){ + data[3][i] = this.paretoLine[0] + this.paretoLine[1]*paretoOrderMedians[i]; + } + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("Pareto Order Statistic Medians"); + pg.setYaxisLegend("Ordered Data Values"); + pg.setGraphTitle("Pareto probability plot: gradient = " + Fmath.truncate(this.paretoLine[1], 4) + ", intercept = " + Fmath.truncate(this.paretoLine[0], 4) + ", R = " + Fmath.truncate(this.paretoCorrCoeff, 4)); + pg.setGraphTitle2(" alpha = " + Fmath.truncate(this.paretoParam[0], 4) + ", beta = " + Fmath.truncate(this.paretoParam[1], 4)); + + // Plot + pg.plot(); + + this.paretoDone = true; + this.probPlotDone = true; + } + + // Return Pareto alpha + public double paretoAlpha(){ + if(!this.paretoDone)throw new IllegalArgumentException("Pareto Probability Plot method has not been called"); + return this.paretoParam[0]; + } + + // Return Pareto alpha error + public double paretoAlphaError(){ + if(!this.paretoDone)throw new IllegalArgumentException("Pareto Probability Plot method has not been called"); + return this.paretoParamErrors[0]; + } + + // Return Pareto beta + public double paretoBeta(){ + if(!this.paretoDone)throw new IllegalArgumentException("Pareto Probability Plot method has not been called"); + return this.paretoParam[1]; + } + + // Return Pareto beta error + public double paretoBetaError(){ + if(!this.paretoDone)throw new IllegalArgumentException("Pareto Probability Plot method has not been called"); + return this.paretoParamErrors[1]; + } + + // Return Pareto order statistic medians + public double[] paretoOrderStatisticMedians(){ + if(!this.paretoDone)throw new IllegalArgumentException("Pareto Probability Plot method has not been called"); + return this.paretoOrderMedians; + } + + // Return the Pareto gradient + public double paretoGradient(){ + if(!this.paretoDone)throw new IllegalArgumentException("Pareto Probability Plot method has not been called"); + return this.paretoLine[1]; + } + + // Return the error of the Pareto gradient + public double paretoGradientError(){ + if(!this.paretoDone)throw new IllegalArgumentException("Pareto Probability Plot method has not been called"); + return this.paretoLineErrors[1]; + } + + // Return the Pareto intercept + public double paretoIntercept(){ + if(!this.paretoDone)throw new IllegalArgumentException("Pareto Probability Plot method has not been called"); + return this.paretoLine[0]; + } + + // Return the error of the Pareto intercept + public double paretoInterceptError(){ + if(!this.paretoDone)throw new IllegalArgumentException("Pareto Probability Plot method has not been called"); + return this.paretoLineErrors[0]; + } + + // Return the Pareto correlation coefficient + public double paretoCorrelationCoefficient(){ + if(!this.paretoDone)throw new IllegalArgumentException("Pareto Probability Plot method has not been called"); + return this.paretoCorrCoeff; + } + + // Return the sum of squares at the Pareto minimum + public double paretoSumOfSquares(){ + if(!this.paretoDone)throw new IllegalArgumentException("Pareto Probability Plot method has not been called"); + return this.paretoSumOfSquares; + } + + + // F-DISTRIBUTION PROBABILITY PLOT + public void fDistributionProbabilityPlot(int nu1, int nu2){ + this.lastMethod = 15; + + // Check for suffient data points + this.fDistributionNumberOfParameters = 0; + if(this.numberOfDataPoints<3)throw new IllegalArgumentException("There must be at least three data points - preferably considerably more"); + + // Calculate Exponential order statistic medians + this.fDistributionOrderMedians = Stat.fDistributionOrderStatisticMedians(nu1, nu2, this.numberOfDataPoints); + + // Regression of the ordered data on the F-distribution order statistic medians + Regression reg = new Regression(this.fDistributionOrderMedians, this.sortedData); + reg.linear(); + + // Intercept and gradient of best fit straight line + this.fDistributionLine = reg.getBestEstimates(); + + // Estimated erors of the intercept and gradient of best fit straight line + this.fDistributionLineErrors = reg.getBestEstimatesErrors(); + + // Correlation coefficient + this.fDistributionCorrCoeff = reg.getSampleR(); + + // Initialize data arrays for plotting + double[][] data = PlotGraph.data(2,this.numberOfDataPoints); + + // Assign data to plotting arrays + data[0] = this.fDistributionOrderMedians; + data[1] = this.sortedData; + + data[2] = fDistributionOrderMedians; + for(int i=0; i<this.numberOfDataPoints; i++){ + data[3][i] = this.fDistributionLine[0] + this.fDistributionLine[1]*fDistributionOrderMedians[i]; + } + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(data); + int[] points = {4, 0}; + pg.setPoint(points); + int[] lines = {0, 3}; + pg.setLine(lines); + pg.setXaxisLegend("F-distribution Order Statistic Medians"); + pg.setYaxisLegend("Ordered Data Values"); + pg.setGraphTitle("F-distribution probability plot: gradient = " + Fmath.truncate(this.fDistributionLine[1], 4) + ", intercept = " + Fmath.truncate(this.fDistributionLine[0], 4) + ", R = " + Fmath.truncate(this.fDistributionCorrCoeff, 4)); + pg.setGraphTitle2(" nu1 = " + nu1 + ", nu2 = " + nu2); + + // Plot + pg.plot(); + + this.fDistributionDone = true; + this.probPlotDone = true; + } + + // Return F-distribution order statistic medians + public double[] fDistributionOrderStatisticMedians(){ + if(!this.fDistributionDone)throw new IllegalArgumentException("F-distribution Probability Plot method has not been called"); + return this.fDistributionOrderMedians; + } + + // Return the F-distribution gradient + public double fDistributionGradient(){ + if(!this.fDistributionDone)throw new IllegalArgumentException("F-distribution Probability Plot method has not been called"); + return this.fDistributionLine[1]; + } + + // Return the error of the F-distribution gradient + public double fDistributionGradientError(){ + if(!this.fDistributionDone)throw new IllegalArgumentException("F-distribution Probability Plot method has not been called"); + return this.fDistributionLineErrors[1]; + } + + // Return the F-distribution intercept + public double fDistributionIntercept(){ + if(!this.fDistributionDone)throw new IllegalArgumentException("F-distribution Probability Plot method has not been called"); + return this.fDistributionLine[0]; + } + + // Return the error of the F-distribution intercept + public double fDistributionInterceptError(){ + if(!this.fDistributionDone)throw new IllegalArgumentException("F-distribution Probability Plot method has not been called"); + return this.fDistributionLineErrors[0]; + } + + // Return the F-distribution correlation coefficient + public double fDistributionCorrelationCoefficient(){ + if(!this.fDistributionDone)throw new IllegalArgumentException("F-distribution Probability Plot method has not been called"); + return this.fDistributionCorrCoeff; + } + + // Return the sum of squares at the F-distribution minimum + public double fDistributionSumOfSquares(){ + if(!this.fDistributionDone)throw new IllegalArgumentException("F-distribution Probability Plot method has not been called"); + return this.fDistributionSumOfSquares; + } + + + + // COMMON METHODS + + // Return the ordered data + public double[] orderedData(){ + return this.sortedData; + } + + // Return the number of data points + public int numberOfDataPoints(){ + return this.numberOfDataPoints; + } + + // Return the data mean + public double mean(){ + return this.mean; + } + + // Return the data standard deviation + public double standardDeviation(){ + if(!this.probPlotDone)throw new IllegalArgumentException("no probability plot method has been called"); + return this.standardDeviation; + } + + // Return the data minimum + public double minimum(){ + return this.minimum; + } + + // Return the data maximum + public double maximum(){ + return this.maximum; + } + + // Return the numerical differentiation step, delta + public double delta(){ + return this.delta; + } + + // Reset the numerical differentiation step, delta + public void resetDelta(double delta){ + this.delta = delta; + } + + // Set standard deviation denominator to n + public void setDenominatorToN(){ + this.nFactorOptionI = true; + this.arrayAsStat.setDenominatorToN(); + this.standardDeviation = arrayAsStat.standardDeviation(); + this.nFactorReset = true; + } + + // Set standard deviation denominator to n-1 + public void setDenominatorToNminusOne(){ + this.nFactorOptionI = false; + arrayAsStat.setDenominatorToNminusOne(); + this.standardDeviation = arrayAsStat.standardDeviation(); + this.nFactorReset = true; + } + + // Return initial estimates used in last call to a probability plot method + public double[] getInitialEstimates(){ + return this.initialEstimates; + } + +} + + + +// PROBABILITY PLOT FUNCTIONS +// Gaussian Probabilty plot function +class GaussProbPlotFunc implements RegressionFunction{ + + private int nPoints = 0; + private int index = 0; + private double[] medians = null; + + public double function(double[] p, double[] x){ + + // Calculate Gaussian order statistic medians + if(index==0)medians = Stat.gaussianOrderStatisticMedians(p[0], p[1], nPoints); + + // return median value + double y = medians[index]; + index++; + if(index==nPoints)index=0; + return y; + } + + public void setDataArray(int nPoints){ + this.nPoints = nPoints; + } +} + + + +// Exponential Probabilty plot function +class ExponentialProbPlotFunc implements RegressionFunction{ + + private int nPoints = 0; + private int index = 0; + private double[] medians = null; + + public double function(double[] p, double[] x){ + + // Calculate Exponential order statistic medians + if(index==0)medians = Stat.exponentialOrderStatisticMedians(p[0], p[1], nPoints); + + // return median value + double y = medians[index]; + index++; + if(index==nPoints)index=0; + return y; + } + + public void setDataArray(int nPoints){ + this.nPoints = nPoints; + } +} + + + + +// Frechet Probabilty plot function +class FrechetProbPlotFunc implements RegressionFunction{ + + private int nPoints = 0; + private int index = 0; + private double[] medians = null; + + public double function(double[] p, double[] x){ + + // Calculate Frechet order statistic medians + if(index==0)medians = Stat.frechetOrderStatisticMedians(p[0], p[1], p[2], nPoints); + + // return median value + double y = medians[index]; + index++; + if(index==nPoints)index=0; + return y; + } + + public void setDataArray(int nPoints){ + this.nPoints = nPoints; + } +} + + +// Gumbel (minimum order statistic) Probabilty plot function +class GumbelMinProbPlotFunc implements RegressionFunction{ + + private int nPoints = 0; + private int index = 0; + private double[] medians = null; + + + public double function(double[] p, double[] x){ + + // Calculate Gumbel order statistic medians + if(index==0)medians = Stat.gumbelMinOrderStatisticMedians(p[0], p[1], nPoints); + + // return median value + double y = medians[index]; + index++; + if(index==nPoints)index=0; + return y; + } + + public void setDataArray(int nPoints){ + this.nPoints = nPoints; + } +} + + + +// Gumbel (maximum order statistic) Probabilty plot function +class GumbelMaxProbPlotFunc implements RegressionFunction{ + + private int nPoints = 0; + private int index = 0; + private double[] medians = null; + + public double function(double[] p, double[] x){ + + // Calculate Gumbel order statistic medians + if(index==0)medians = Stat.gumbelMaxOrderStatisticMedians(p[0], p[1], nPoints); + + // return median value + double y = medians[index]; + index++; + if(index==nPoints)index=0; + return y; + } + + public void setDataArray(int nPoints){ + this.nPoints = nPoints; + } +} + + +// Logistic Probabilty plot function +class LogisticProbPlotFunc implements RegressionFunction{ + + private int nPoints = 0; + private int index = 0; + private double[] medians = null; + + public double function(double[] p, double[] x){ + + // Calculate Logistic order statistic medians + if(index==0)medians = Stat.logisticOrderStatisticMedians(p[0], p[1], nPoints); + + // return median value + double y = medians[index]; + index++; + if(index==nPoints)index=0; + return y; + } + + public void setDataArray(int nPoints){ + this.nPoints = nPoints; + } +} + + + +// Pareto Probabilty plot function +class ParetoProbPlotFunc implements RegressionFunction{ + + private int nPoints = 0; + private int index = 0; + private double[] medians = null; + + public double function(double[] p, double[] x){ + + // Calculate Pareto order statistic medians + if(index==0)medians = Stat.paretoOrderStatisticMedians(p[0], p[1], nPoints); + + // return median value + double y = medians[index]; + index++; + if(index==nPoints)index=0; + return y; + } + + public void setDataArray(int nPoints){ + this.nPoints = nPoints; + } +} + +// Rayleigh Probabilty plot function +class RayleighProbPlotFunc implements RegressionFunction{ + + private int nPoints = 0; + private int index = 0; + private double[] medians = null; + + + public double function(double[] p, double[] x){ + + // Calculate Rayleigh order statistic medians + if(index==0)medians = Stat.rayleighOrderStatisticMedians(p[0], nPoints); + + // return median value + double y = medians[index]; + index++; + if(index==nPoints)index=0; + return y; + } + + public void setDataArray(int nPoints){ + this.nPoints = nPoints; + } +} + +// Weibull Probabilty plot function +// Three parameter +class WeibullProbPlotFunc implements RegressionFunction{ + + private int nPoints = 0; + private int index = 0; + private double[] medians = null; + + public double function(double[] p, double[] x){ + + // Calculate Weibull order statistic medians + if(index==0)medians = Stat.weibullOrderStatisticMedians(p[0], p[1], p[2], nPoints); + + // return median value + double y = medians[index]; + index++; + if(index==nPoints)index=0; + return y; + } + + public void setDataArray(int nPoints){ + this.nPoints = nPoints; + } +} + +// Weibull Probabilty plot function +// Two parameter +class WeibullTwoParProbPlotFunc implements RegressionFunction{ + + private int nPoints = 0; + private int index = 0; + private double[] medians = null; + + public double function(double[] p, double[] x){ + + // Calculate Weibull order statistic medians + if(index==0)medians = Stat.weibullOrderStatisticMedians(p[0], p[1], nPoints); + + // return median value + double y = medians[index]; + index++; + if(index==nPoints)index=0; + return y; + + } + + public void setDataArray(int nPoints){ + this.nPoints = nPoints; + } +} + +// Weibull Probabilty plot function +// Standard (one parameter) +class WeibullStandardProbPlotFunc implements RegressionFunction{ + + private int nPoints = 0; + private int index = 0; + private double[] medians = null; + + public double function(double[] p, double[] x){ + + // Calculate Weibull order statistic medians + if(index==0)medians = Stat.weibullOrderStatisticMedians(p[0], nPoints); + + // return median value + double y = medians[index]; + index++; + if(index==nPoints)index=0; + return y; + + } + + public void setDataArray(int nPoints){ + this.nPoints = nPoints; + } +} + diff --git a/src/main/java/flanagan/analysis/RankAnalysis.java b/src/main/java/flanagan/analysis/RankAnalysis.java new file mode 100755 index 0000000000000000000000000000000000000000..d882905ee0f7b91f1c157243234fb1d114097e49 --- /dev/null +++ b/src/main/java/flanagan/analysis/RankAnalysis.java @@ -0,0 +1,874 @@ +/* +* Class RankAnalysis +* +* USAGE: Matrix Rank Analysis +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: August - September 2008 +* UPDATE: 12 October 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/RankAnalysis.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.analysis; + +import flanagan.analysis.Stat; +import flanagan.analysis.Cronbach; +import flanagan.math.Fmath; +import flanagan.math.Matrix; +import flanagan.math.ArrayMaths; +import flanagan.io.FileOutput; + +import java.util.ArrayList; +import java.util.Vector; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.*; +import java.text.*; + +public class RankAnalysis{ + + private double[][] values = null; // matrix of values whose rank is required + private double[][] errors = null; // matrix of errors of the values + + private double[] valuesDiagonal = null; // diagonal of values whose rank is required + private double[] errorsDiagonal = null; // diagonal of errors of the values + + private double[][] reducedValues = null; // reduced matrix of values whose rank is required + private double[][] reducedErrors = null; // reduced matrix of standard deviations of the values + + private double[] reducedValuesDiagonal = null; // diagonal of reduced values + private double[] reducedErrorsDiagonal = null; // diagonal of reduved errors + private double[] reducedValueOverError = null; // ratio of reduced value diagonal over reduced error diagonal + private double[] probabilityValues = null; // P-values for above ratios + private double[] mcMullen = null; // Criteria of McMullen, Jaskunas and Tinoco + + private int numberOfRows = 0; // number of rows + private int numberOfColumns = 0; // number of columns + private int diagonalLength = 0; // length of diagonal + + private int errorType = 3; // = 0 matrix of individual errors supplied + // = 1 common error for all elements in each each row supplied + // = 2 single common error for all elements in the matrix supplied + // = 3 no error/s supplied + + private double[] errorRowMeans = null; // means of the rows of errors + private double[] errorColumnMeans = null; // means of the columns of errors + + private int numberOfMissingErrors = 0; // number of missing errors (entered as NaN) + private boolean rowOption = true; // = true - missing errors replaced by the appropriate row mean + // = false - missing errors replaced by the appropriate column mean + + private boolean rankAnalysisDone = false; // = true when rank analysis performed + + + // CONSTRUCTORS + // Individual error for each value + public RankAnalysis(double[][] values, double[][] errors){ + this.values = values; + this.errors = errors; + this.errorType = 0; + this.preprocessDataOne(); + } + + public RankAnalysis(float[][] values, float[][] errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + Matrix mate = new Matrix(errors); + this.errors = mate.getArrayCopy(); + this.errorType = 0; + this.preprocessDataOne(); + } + + public RankAnalysis(long[][] values, long[][] errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + Matrix mate = new Matrix(errors); + this.errors = mate.getArrayCopy(); + this.errorType = 0; + this.preprocessDataOne(); + } + + public RankAnalysis(int[][] values, int[][] errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + Matrix mate = new Matrix(errors); + this.errors = mate.getArrayCopy(); + this.errorType = 0; + this.preprocessDataOne(); + } + + public RankAnalysis(BigDecimal[][] values, BigDecimal[][] errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + Matrix mate = new Matrix(errors); + this.errors = mate.getArrayCopy(); + this.errorType = 0; + this.preprocessDataOne(); + } + + public RankAnalysis(BigInteger[][] values, BigInteger[][] errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + Matrix mate = new Matrix(errors); + this.errors = mate.getArrayCopy(); + this.errorType = 0; + this.preprocessDataOne(); + } + + public RankAnalysis(ArrayMaths[] values, ArrayMaths[] errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + Matrix mate = new Matrix(errors); + this.errors = mate.getArrayCopy(); + this.errorType = 0; + this.preprocessDataOne(); + } + + public RankAnalysis(ArrayList<Object>[] values, ArrayList<Object>[] errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + Matrix mate = new Matrix(errors); + this.errors = mate.getArrayCopy(); + this.errorType = 0; + this.preprocessDataOne(); + } + + public RankAnalysis(Vector<Object>[] values, Vector<Object>[] errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + Matrix mate = new Matrix(errors); + this.errors = mate.getArrayCopy(); + this.errorType = 0; + this.preprocessDataOne(); + } + + public RankAnalysis(Matrix values, Matrix errors){ + this.values = values.getArrayCopy(); + this.errors = errors.getArrayCopy(); + this.errorType = 0; + this.preprocessDataOne(); + } + + + + // Common error for each row + public RankAnalysis(double[][] values, double[] errors){ + this.values = values; + this.errors = this.oneToTwo(errors, this.values[0].length); + this.errorType = 1; + this.preprocessDataOne(); + } + + public RankAnalysis(float[][] values, float[] errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + ArrayMaths ame = new ArrayMaths(errors); + this.errors = this.oneToTwo(ame.array(), this.values[0].length); + this.errorType = 1; + this.preprocessDataOne(); + } + + + public RankAnalysis(long[][] values, long[] errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + ArrayMaths ame = new ArrayMaths(errors); + this.errors = this.oneToTwo(ame.array(), this.values[0].length); + this.errorType = 1; + this.preprocessDataOne(); + } + + public RankAnalysis(int[][] values, int[] errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + ArrayMaths ame = new ArrayMaths(errors); + this.errors = this.oneToTwo(ame.array(), this.values[0].length); + this.errorType = 1; + this.preprocessDataOne(); + } + + public RankAnalysis(BigDecimal[][] values, BigDecimal[] errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + ArrayMaths ame = new ArrayMaths(errors); + this.errors = this.oneToTwo(ame.array(), this.values[0].length); + this.errorType = 1; + this.preprocessDataOne(); + } + + public RankAnalysis(BigInteger[][] values, BigInteger[] errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + ArrayMaths ame = new ArrayMaths(errors); + this.errors = this.oneToTwo(ame.array(), this.values[0].length); + this.errorType = 1; + this.preprocessDataOne(); + } + + public RankAnalysis(ArrayMaths[] values, ArrayMaths errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errors = this.oneToTwo(errors.array(), this.values[0].length); + this.errorType = 1; + this.preprocessDataOne(); + } + + public RankAnalysis(ArrayList<Object>[] values, ArrayList<Object> errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + ArrayMaths ame = new ArrayMaths(errors); + this.errors = this.oneToTwo(ame.array(), this.values[0].length); + this.errorType = 1; + this.preprocessDataOne(); + } + + public RankAnalysis(Vector<Object>[] values, Vector<Object> errors){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + ArrayMaths ame = new ArrayMaths(errors); + this.errors = this.oneToTwo(ame.array(), this.values[0].length); + this.errorType = 1; + this.preprocessDataOne(); + } + + public RankAnalysis(Scores values){ + this.values = values.usedScoresAsRowPerItem(); + Matrix mat = new Matrix(this.values); + double[] errors = mat.rowStandardDeviations(); + ArrayMaths ame = new ArrayMaths(errors); + this.errors = this.oneToTwo(ame.array(), this.values[0].length); + this.errorType = 1; + this.preprocessDataOne(); + } + + public RankAnalysis(Cronbach values){ + this.values = values.usedScoresAsRowPerItem(); + Matrix mat = new Matrix(this.values); + double[] errors = mat.rowStandardDeviations(); + ArrayMaths ame = new ArrayMaths(errors); + this.errors = this.oneToTwo(ame.array(), this.values[0].length); + this.errorType = 1; + this.preprocessDataOne(); + } + + public RankAnalysis(PCA values){ + this.values = values.usedScoresAsRowPerItem(); + Matrix mat = new Matrix(this.values); + double[] errors = mat.rowStandardDeviations(); + ArrayMaths ame = new ArrayMaths(errors); + this.errors = this.oneToTwo(ame.array(), this.values[0].length); + this.errorType = 1; + this.preprocessDataOne(); + } + + // Common error for all values + public RankAnalysis(double[][] values, double commonError){ + this.values = values; + this.errorType = 2; + this.preprocessDataTwo(commonError); + } + + public RankAnalysis(float[][] values, float commonError){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 2; + this.preprocessDataTwo((double)commonError); + } + + public RankAnalysis(long[][] values, long commonError){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 2; + this.preprocessDataTwo((double)commonError); + } + + public RankAnalysis(int[][] values, int commonError){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 2; + this.preprocessDataTwo((double)commonError); + } + + public RankAnalysis(BigDecimal[][] values, BigDecimal commonError){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 2; + this.preprocessDataTwo(commonError.doubleValue()); + } + + public RankAnalysis(BigInteger[][] values, BigInteger commonError){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 2; + this.preprocessDataTwo(commonError.doubleValue()); + } + + public RankAnalysis(ArrayMaths[] values, double commonError){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 2; + this.preprocessDataTwo(commonError); + } + + public RankAnalysis(ArrayList<Object>[] values, double commonError){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 2; + this.preprocessDataTwo(commonError); + } + + public RankAnalysis(Vector<Object>[] values, double commonError){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 2; + this.preprocessDataTwo(commonError); + } + + public RankAnalysis(Matrix values, double commonError){ + this.values = values.getArrayCopy(); + this.errorType = 2; + this.preprocessDataTwo(commonError); + } + + + + // No errors supplied + public RankAnalysis(double[][] values){ + this.values = values; + this.errorType = 3; + this.preprocessDataThree(); + } + + public RankAnalysis(float[][] values){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 3; + this.preprocessDataThree(); + } + + public RankAnalysis(long[][] values){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 3; + this.preprocessDataThree(); + } + + public RankAnalysis(int[][] values){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 3; + this.preprocessDataThree(); + } + + public RankAnalysis(BigDecimal[][] values){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 3; + this.preprocessDataThree(); + } + + public RankAnalysis(BigInteger[][] values){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 3; + this.preprocessDataThree(); + } + + public RankAnalysis(ArrayMaths[] values){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 3; + this.preprocessDataThree(); + } + + public RankAnalysis(ArrayList<Object>[] values){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 3; + this.preprocessDataThree(); + } + + public RankAnalysis(Vector<Object>[] values){ + Matrix matv = new Matrix(values); + this.values = matv.getArrayCopy(); + this.errorType = 3; + this.preprocessDataThree(); + } + + public RankAnalysis(Matrix values){ + this.values = values.getArrayCopy(); + this.errorType = 3; + this.preprocessDataThree(); + } + + + + + // Convets common error per row to individual errors for all rows + private double[][] oneToTwo(double[] errors, int nCols){ + int nRows = errors.length; + double[][] ret = new double[nRows][nCols]; + for(int i=0; i<nRows; i++){ + for(int j=0; j<nCols; j++){ + ret[i][j] = errors[i]; + } + } + return ret; + } + + + // Preprocess data with individual errors supplied directly + // or after common row error converted to individual errors by private method oneToTwo() + private void preprocessDataOne(){ + // Check row and column lengths + this.numberOfRows = this.values.length; + this.numberOfColumns = this.values[0].length; + for(int i=1; i<this.numberOfRows; i++){ + if(this.values[i].length!=this.numberOfColumns)throw new IllegalArgumentException("All rows of the value matrix must be of the same length"); + } + for(int i=0; i<this.numberOfRows; i++){ + if(this.errors[i].length!=this.numberOfColumns)throw new IllegalArgumentException("All rows of the error matrix must be of the same length as those of the value matrix"); + } + this.diagonalLength = this.numberOfRows; + if(this.numberOfRows>this.numberOfColumns)this.diagonalLength = this.numberOfColumns; + + // Convert errors to variances + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + this.errors[i][j] *= this.errors[i][j]; + } + } + } + + // Preprocess data witha single common error supplied + private void preprocessDataTwo(double commonError){ + // Check row and column lengths + this.numberOfRows = this.values.length; + this.numberOfColumns = this.values[0].length; + for(int i=1; i<this.numberOfRows; i++){ + if(this.values[i].length!=this.numberOfColumns)throw new IllegalArgumentException("All rows of the value matrix must be of the same length"); + } + this.diagonalLength = this.numberOfRows; + if(this.numberOfRows>this.numberOfColumns)this.diagonalLength = this.numberOfColumns; + + // Fill errors matrix + this.errors = new double[this.numberOfRows][this.numberOfColumns]; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + this.errors[i][j] = commonError*commonError; + } + } + } + + // Preprocess data with no errors supplied + // Each error substituted by a very rough estimate of the potential rounding error + private void preprocessDataThree(){ + // Check row and column lengths + this.numberOfRows = this.values.length; + this.numberOfColumns = this.values[0].length; + for(int i=1; i<this.numberOfRows; i++){ + if(this.values[i].length!=this.numberOfColumns)throw new IllegalArgumentException("All rows of the value matrix must be of the same length"); + } + this.diagonalLength = this.numberOfRows; + if(this.numberOfRows>this.numberOfColumns)this.diagonalLength = this.numberOfColumns; + + // Fill errors matrix + this.errors = new double[this.numberOfRows][this.numberOfColumns]; + double error = 0.0; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + error = Math.pow(10.0, Math.floor(Math.log10(Math.abs(this.values[i][j]))))*5.0E-16; + this.errors[i][j] = error*error; + } + } + } + + // Missing error options + // Use error row mean to replace a missing error + // This is the default option + public void useErrorRowMean(){ + this.rowOption = true; + } + + // Use error column mean to replace a missing error + public void useErrorColumnMean(){ + this.rowOption = false; + } + + // Return number of replaced missing errors + public int nMissingErrors(){ + return this.numberOfMissingErrors; + } + + + // Rank analysis + private void rankAnalysis(){ + + // Check errors for negative values and missing values (entered as NaN) + + // Row means and negative errors multiplied by -1 + this.errorRowMeans = new double[this.numberOfRows]; + this.errorColumnMeans = new double[this.numberOfColumns]; + this.numberOfMissingErrors = 0; + for(int i=0; i<this.numberOfRows; i++){ + int counter = 0; + for(int j=0; j<this.numberOfColumns; j++){ + if(!Double.isNaN(this.errors[i][j])){ + if(this.errors[i][j]<0.0)this.errors[i][j] *= -1.0; + this.errorRowMeans[i] += this.errors[i][j]; + counter++; + } + else{ + this.numberOfMissingErrors++; + } + } + this.errorRowMeans[i] /= counter; + } + + // Column means + for(int i=0; i<this.numberOfColumns; i++){ + int counter = 0; + for(int j=0; j<this.numberOfRows; j++){ + if(!Double.isNaN(this.errors[j][i])){ + this.errorColumnMeans[i] += this.errors[j][i]; + counter++; + } + } + this.errorColumnMeans[i] /= counter; + } + + // missing errors replaced by the row or column mean excluding the missing values (see missingErrorOption); + if(this.numberOfMissingErrors>0){ + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(Double.isNaN(this.errors[i][j])){ + if(this.rowOption){ + this.errors[i][j] = errorRowMeans[i]; + } + else{ + this.errors[i][j] = errorColumnMeans[i]; + } + } + } + } + } + + // Matrix reduction + + this.reducedValues = this.values; + this.reducedErrors = this.errors; + Matrix matv0 = new Matrix(this.reducedValues); + Matrix mate0 = new Matrix(this.reducedErrors); + int nn = this.diagonalLength - 1; + + for(int i=0; i<nn; i++){ + matv0 = new Matrix(this.reducedValues); + + // Isolate sub-matrix + int nrow = this.numberOfRows-i; + int ncol = this.numberOfColumns - i; + Matrix mat1 = matv0.getSubMatrix(i, i, this.numberOfRows-1, numberOfColumns-1); + double[][] subv = mat1.getArrayCopy(); + + // Get pivot indices + int[] max = mat1.pivot(); + int pivotI = max[0]+i; + int pivotJ = max[1]+i; + + // Swap rows + double[] holdv1 = this.reducedValues[i]; + double[] holde1 = this.reducedErrors[i]; + this.reducedValues[i] = this.reducedValues[pivotI]; + this.reducedErrors[i] = this.reducedErrors[pivotI]; + this.reducedValues[pivotI] = holdv1; + this.reducedErrors[pivotI] = holde1; + + // Swap columns + double holdv2 = 0.0; + double holde2 = 0.0; + for(int j=0; j<numberOfRows; j++){ + holdv2 = this.reducedValues[j][i]; + holde2 = this.reducedErrors[j][i]; + this.reducedValues[j][i] = this.reducedValues[j][pivotJ]; + this.reducedErrors[j][i] = this.reducedErrors[j][pivotJ]; + this.reducedValues[j][pivotJ] = holdv2; + this.reducedErrors[j][pivotJ] = holde2; + } + + // Reduce sub-matrix + Matrix matValueHold = new Matrix(this.reducedValues); + Matrix matErrorHold = new Matrix(this.reducedErrors); + double[][] valueHold = matValueHold.getArrayCopy(); + double[][] errorHold = matErrorHold.getArrayCopy(); + + for(int j=i+1; j<this.numberOfRows; j++){ + for(int k=i; k<this.numberOfColumns; k++){ + double ratio1 = 1.0; + if(this.reducedValues[j][i]!=this.reducedValues[i][i])ratio1 = this.reducedValues[j][i]/this.reducedValues[i][i]; + valueHold[j][k] = this.reducedValues[j][k] - ratio1*this.reducedValues[i][k]; + double hold = this.reducedErrors[j][k] + this.reducedErrors[i][k]*ratio1*ratio1; + double ratio2 = 1.0; + if(this.reducedValues[i][k]!=this.reducedValues[i][i])ratio2 = this.reducedValues[i][k]/this.reducedValues[i][i]; + hold += this.reducedErrors[j][i]*ratio2*ratio2; + errorHold[j][k] = hold + this.reducedErrors[i][i]*ratio1*ratio1*ratio2*ratio2; + } + } + matValueHold = new Matrix(valueHold); + matErrorHold = new Matrix(errorHold); + this.reducedValues = matValueHold.getArrayCopy(); + this.reducedErrors = matErrorHold.getArrayCopy(); + } + + // Convert errors to standard deviations + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + this.reducedErrors[i][j] = Math.sqrt(this.reducedErrors[i][j]); + } + } + + // Fill zero elements + for(int i=1; i<this.diagonalLength; i++){ + for(int j=0; j<i; j++){ + this.reducedValues[i][j] = 0.0; + this.reducedErrors[i][j] = 0.0; + } + } + + if(this.diagonalLength<this.numberOfRows){ + for(int i=this.diagonalLength; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + this.reducedValues[i][j] = 0.0; + this.reducedErrors[i][j] = 0.0; + } + } + } + + // store diagonals and calculate probability values + this.reducedValuesDiagonal = new double[this.diagonalLength]; + this.reducedErrorsDiagonal = new double[this.diagonalLength]; + this.reducedValueOverError = new double[this.diagonalLength]; + this.probabilityValues = new double[this.diagonalLength]; + this.mcMullen = new double[this.diagonalLength]; + + for(int i=0; i<this.diagonalLength; i++){ + this.reducedValuesDiagonal[i] = this.reducedValues[i][i]; + this.reducedErrorsDiagonal[i] = this.reducedErrors[i][i]; + this.reducedValueOverError[i] = Math.abs(this.reducedValuesDiagonal[i]/this.reducedErrorsDiagonal[i]); + this.probabilityValues[i] = 1.0 - Stat.gaussianCDF(0.0, 1.0, -this.reducedValueOverError[i], this.reducedValueOverError[i]); + } + + // calculate criteria of McMullen, Jaskunas and Tinoco + for(int i=0; i<this.numberOfRows; i++){ + double sum = 0.0; + for(int j=i; j<this.numberOfColumns; j++){ + sum += this.reducedValues[i][j]*this.reducedValues[i][j]; + } + this.mcMullen[i] = Math.sqrt(sum)/(this.numberOfColumns-i); + } + + this.rankAnalysisDone = true; + } + + // Return an analysis to a text file + public void analysis(){ + this.analysis("RankAnalysisOutput.txt"); + } + + public void analysis(String fileName){ + if(!this.rankAnalysisDone)this.rankAnalysis(); + + int posdot = fileName.indexOf("."); + if(posdot==-1)fileName = fileName + ".txt"; + + FileOutput fout = new FileOutput(fileName); + fout.println("Rank Analysis"); + fout.println("File name: " + fileName); + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + fout.println("Program executed at " + tim + " on " + day); + fout.println(); + + fout.println("Number of rows " + this.numberOfRows); + fout.println("Number of columns " + this.numberOfColumns); + if(this.numberOfMissingErrors>0){ + fout.println("Number of substituted missing errors" + this.numberOfMissingErrors); + if(this.rowOption){ + fout.println("Row means used as the substituted value/s"); + } + else{ + fout.println("Column means used as the substituted value/s"); + } + } + fout.println(); + + switch(this.errorType){ + case 0: fout.println("Matrix of individual errors supplied"); + break; + case 1: fout.println("Common error for all elements in each each row supplied"); + break; + case 2: fout.println("Single common error for all elements in the matrix supplied"); + break; + case 3: fout.println("No errors supplied - estimate of the rounding errors used"); + } + fout.println(); + + int field1 = 30; + int field2 = 15; + int trunc = 4; + if(this.errorType!=3){ + fout.print("Reduced", field2); + fout.print("Reduced", field2); + fout.print("V/E Ratio", field2); + fout.print("P-value", field2); + fout.println("McMullen"); + + fout.print("Value", field2); + fout.print("Error", field2); + fout.print(" ", field2); + fout.print(" ", field2); + fout.println("rms"); + + fout.print("Diagonal (V)", field2); + fout.print("Diagonal (E)", field2); + fout.print(" ", field2); + fout.print(" ", field2); + fout.println(" "); + } + else{ + fout.print("Reduced", field2); + fout.print("Reduced", field2); + fout.print("V/E Ratio", field2); + fout.print("P-value", field2); + fout.println("McMullen"); + + fout.print("Value", field2); + fout.print("Estimated", field2); + fout.print(" ", field2); + fout.print(" ", field2); + fout.println("rms"); + + fout.print("Diagonal (V)", field2); + fout.print("Rounding", field2); + fout.print(" ", field2); + fout.print(" ", field2); + fout.println(" "); + + fout.print(" ", field2); + fout.print("Error (E)", field2); + fout.print(" ", field2); + fout.print(" ", field2); + fout.println(" "); + } + + for(int i=0; i<this.diagonalLength; i++){ + fout.print(Fmath.truncate(this.reducedValuesDiagonal[i], trunc), field2); + fout.print(Fmath.truncate(this.reducedErrorsDiagonal[i], trunc), field2); + fout.print(Fmath.truncate(this.reducedValueOverError[i], trunc), field2); + fout.print(Fmath.truncate(this.probabilityValues[i], trunc), field2); + fout.println(Fmath.truncate(this.mcMullen[i], trunc)); + } + + System.out.println("Analysis written to text file " + fileName); + + fout.close(); + } + + + // Return original values matrix + public double[][] originalValues(){ + if(!this.rankAnalysisDone)this.rankAnalysis(); + return this.values; + } + + // Return original error matrix + public double[][] originalErrors(){ + if(!this.rankAnalysisDone)this.rankAnalysis(); + return this.errors; + } + + // Return reduced values matrix + public double[][] reducedValues(){ + if(!this.rankAnalysisDone)this.rankAnalysis(); + return this.reducedValues; + } + + // Return reduced errors matrix + public double[][] reducedErrors(){ + if(!this.rankAnalysisDone)this.rankAnalysis(); + return this.reducedErrors; + } + + // Return reduced values diagonal + public double[] reducedValuesDiagonal(){ + if(!this.rankAnalysisDone)this.rankAnalysis(); + return this.reducedValuesDiagonal; + } + + // Return reduced errors diagonal + public double[] reducedErrorsDiagonal(){ + if(!this.rankAnalysisDone)this.rankAnalysis(); + return this.reducedErrorsDiagonal; + } + + // Return reduced value over reduced errors diagonal + public double[] reducedRatiosDiagonal(){ + if(!this.rankAnalysisDone)this.rankAnalysis(); + return this.reducedValueOverError; + } + + // Return probabilty values diagonal + public double[] probabilityValues(){ + if(!this.rankAnalysisDone)this.rankAnalysis(); + return this.probabilityValues; + } + + // Return McMullen values + public double[] mcMullenValues(){ + if(!this.rankAnalysisDone)this.rankAnalysis(); + return this.mcMullen; + } + + // return number of rows + public int nRows(){ + if(!this.rankAnalysisDone)this.rankAnalysis(); + return this.numberOfRows; + } + + // return number of columns + public int nColumns(){ + if(!this.rankAnalysisDone)this.rankAnalysis(); + return this.numberOfColumns; + } + + // return number of diagonal elements + public int nDiagonalElements(){ + if(!this.rankAnalysisDone)this.rankAnalysis(); + return this.diagonalLength; + } + +} \ No newline at end of file diff --git a/src/main/java/flanagan/analysis/Regression.java b/src/main/java/flanagan/analysis/Regression.java new file mode 100755 index 0000000000000000000000000000000000000000..b511a486d2106e25af389948f027d6113063714d --- /dev/null +++ b/src/main/java/flanagan/analysis/Regression.java @@ -0,0 +1,10048 @@ +/* +* Class Regression +* +* Contains methods for simple linear regression +* (straight line), for multiple linear regression, +* for fitting data to a polynomial, for non-linear +* regression (Nelder and Mead Simplex method), +* and for fitting data to a Gaussian distribution, +* a Log-Normal distribution, a Logistics distribution, +* a Lorentzian distribution, a Poisson distribution, +* a Beta distribution, a Gamma distribution, +* an Erlang distribution, a Gumbel distribution, +* a Frechet distrubution, a Weibull distribution, +* an Exponential distribution, a simple exponential, +* multiple exponentials, a Rayleigh distribution, +* a Pareto distribution, a rectangular hyberbola, +* a sigmoid threshold function, a x^n/(theta^n + x^n) sigmoid function, +* and a scaled Heaviside step function. +* +* The sum of squares function needed by the +* non-linear regression methods is supplied by +* means of the interface, RegressionFunction +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: February 2002 +* MODIFIED: 7 January 2006, 28 July 2006, 9 August 2006, 4 November 2006 +* 21 November 2006, 21 December 2006, 14 April 2007, 9 June 2007, +* 25 July 2007, 23/24 August 2007, 14 September 2007, 28 December 2007 +* 18-26 March 2008, 7 April 2008, 27 April 2008, 10/12/19 May 2008, +* 5-6 July 2004, 28 July 2008, 29 August 2008, 5 September 2008, +* 6 October 2008, 13-15 October 2009 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Regression.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + + +package flanagan.analysis; + +import java.util.*; +import javax.swing.JOptionPane; +import flanagan.math.*; +import flanagan.io.*; +import flanagan.plot.Plot; +import flanagan.plot.PlotGraph; +import flanagan.analysis.*; +import flanagan.circuits.Impedance; + +// Regression class +public class Regression{ + + protected int nData0=0; // number of y data points inputted (in a single array if multiple y arrays) + protected int nData=0; // number of y data points (nData0 times the number of y arrays) + protected int nXarrays=1; // number of x arrays + protected int nYarrays=1; // number of y arrays + protected int nTerms=0; // number of unknown parameters to be estimated + // multiple linear (a + b.x1 +c.x2 + . . ., = nXarrays + 1 + // polynomial fitting; = polynomial degree + 1 + // generalised linear; = nXarrays + // simplex = no. of parameters to be estimated + protected int degreesOfFreedom=0; // degrees of freedom = nData - nTerms + protected double[][] xData=null; // x data values + protected double[] yData=null; // y data values + protected double[] yCalc=null; // calculated y values using the regrssion coefficients + protected double[] weight=null; // weighting factors + protected double[] residual=null; // residuals + protected double[] residualW=null; // weighted residuals + protected boolean weightOpt=false; // weighting factor option + // = true; weights supplied + // = false; weigths set to unity in regression + // average error used in statistacal methods + // if any weight[i] = zero, + // weighOpt is set to false and + // all weights set to unity + protected int weightFlag=0; // weighting flag - weightOpt = false, weightFlag = 0; weightOpt = true, weightFlag = 1 + protected String[] weightWord = {"", "Weighted "}; + + protected double[] best = null; // best estimates vector of the unknown parameters + protected double[] bestSd =null; // standard deviation estimates of the best estimates of the unknown parameters + protected double[] pseudoSd = null; // Pseudo-nonlinear sd + protected double[] tValues = null; // t-values of the best estimates + protected double[] pValues = null; // p-values of the best estimates + + protected double chiSquare=Double.NaN; // chi square (observed-calculated)^2/variance + protected double reducedChiSquare=Double.NaN; // reduced chi square + protected double sumOfSquares=Double.NaN; // Sum of the squares of the residuals + protected double lastSSnoConstraint=0.0D; // Last sum of the squares of the residuals with no constraint penalty + protected double[][] covar=null; // Covariance matrix + protected double[][] corrCoeff=null; // Correlation coefficient matrix + protected double sampleR = Double.NaN; // coefficient of determination + protected double sampleR2 = Double.NaN; // sampleR2 = sampleR*sampleR + protected double adjustedR = Double.NaN; // adjusted coefficient of determination + protected double adjustedR2 = Double.NaN; // adjustedR2 = adjustedR*adjustedR + protected double multipleF= Double.NaN; // Multiple correlation coefficient F ratio + protected double adjustedF= Double.NaN; // Adjusted Multiple correlation coefficient F ratio + + protected String[] paraName = null; // names of parameters, eg, mean, sd; c[0], c[1], c[2] . . . + protected int prec = 4; // number of places to which double variables are truncated on output to text files + protected int field = 13; // field width on output to text files + + protected int lastMethod=-1; // code indicating the last regression procedure attempted + // = 0 multiple linear regression, y = a + b.x1 +c.x2 . . . + // = 1 polynomial fitting, y = a +b.x +c.x^2 . . . + // = 2 generalised multiple linear y = a.f1(x) + b.f2(x) . . . + // = 3 Nelder and Mead simplex + // = 4 Fit to a Gaussian distribution (see also 38 below) + // = 5 Fit to a Lorentzian distribution + // = 6 Fit to a Poisson distribution + // = 7 Fit to a Two Parameter Gumbel distribution (minimum order statistic) + // = 8 Fit to a Two Parameter Gumbel distribution (maximum order statistic) + // = 9 Fit to a One Parameter Gumbel distribution (minimum order statistic) + // = 10 Fit to One Parameter Gumbel distribution (maximum order statistic) + // = 11 Fit to a Standard Gumbel distribution (minimum order statistic) + // = 12 Fit to a Standard Gumbel distribution (maximum order statistic) + // = 13 Fit to a Three parameter Frechet distribution + // = 14 Fit to a Two Parameter Frechet distribution + // = 15 Fit to a Standard Frechet distribution + // = 16 Fit to a Three parameter Weibull distribution + // = 17 Fit to a Two Parameter Weibull distribution + // = 18 Fit to a Standard Weibull distribution + // = 19 Fit to a Two Parameter Exponential distribution + // = 20 Fit to a One Parameter Exponential distribution + // = 21 Fit to a Standard Parameter Exponential distribution + // = 22 Fit to a Rayleigh distribution + // = 23 Fit to a Two Parameter Pareto distribution + // = 24 Fit to a One Parameter Pareto distribution + // = 25 Fit to a Sigmoidal Threshold Function + // = 26 Fit to a rectangular Hyperbola + // = 27 Fit to a scaled Heaviside Step Function + // = 28 Fit to a Hills/Sips Sigmoid + // = 29 Fit to a Shifted Pareto distribution + // = 30 Fit to a Logistic distribution + // = 31 Fit to a Beta distribution - [0, 1] interval + // = 32 Fit to a Beta distribution - [min, max] interval + // = 33 Fit to a Three Parameter Gamma distribution + // = 34 Fit to a Standard Gamma distribution + // = 35 Fit to an Erlang distribution + // = 36 Fit to a two parameter log-normal distribution + // = 37 Fit to a three parameter log-normal distribution + // = 38 Fit to a Gaussian distribution [allows fixed p-arameters] (see also 4 above) + // = 39 Fit to a EC50 dose response curve + // = 40 Fit to a LogEC50 dose response curve + // = 41 Fit to a EC50 dose response curve - bottom constrained + // = 42 Fit to a LogEC50 dose response curve- bottom constrained + // = 43 Fit to a simple exponential, A.exp(Bx) + // = 44 Fit to a multiple exponentials + + protected boolean userSupplied = true; // = true - user supplies the initial estimates for non-linear regression + // = false - the initial estimates for non-linear regression are calculated internally + + protected double kayValue = 0.0D; // rate parameter value in Erlang distribution (method 35) + + protected boolean frechetWeibull = true; // Frechet Weibull switch - if true Frechet, if false Weibull + protected boolean linNonLin = true; // if true linear method, if false non-linear method + protected boolean trueFreq = false; // true if xData values are true frequencies, e.g. in a fit to Gaussian + // false if not + // if true chiSquarePoisson (see above) is also calculated + protected String xLegend = "x axis values"; // x axis legend in X-Y plot + protected String yLegend = "y axis values"; // y axis legend in X-Y plot + protected String graphTitle = " "; // user supplied graph title + protected boolean legendCheck = false; // = true if above legends overwritten by user supplied legends + protected boolean supressPrint = false; // = true if print results is to be supressed + protected boolean supressYYplot= false; // = true if plot of experimental versus calculated is to be supressed + protected boolean supressErrorMessages= false; // = true if some designated error messages are to be supressed + + // Non-linear members + protected boolean nlrStatus=true; // Status of non-linear regression on exiting regression method + // = true - convergence criterion was met + // = false - convergence criterion not met - current estimates returned + protected int scaleOpt=0; // if = 0; no scaling of initial estimates + // if = 1; initial simplex estimates scaled to unity + // if = 2; initial estimates scaled by user provided values in scale[] + // (default = 0) + protected double[] scale = null; // values to scale initial estimate (see scaleOpt above) + protected boolean zeroCheck = false; // true if any best estimate value is zero + // if true the scale factor replaces the best estimate in numerical differentiation + protected boolean penalty = false; // true if single parameter penalty function is included + protected boolean sumPenalty = false; // true if multiple parameter penalty function is included + protected int nConstraints = 0; // number of single parameter constraints + protected int nSumConstraints = 0; // number of multiple parameter constraints + protected int maxConstraintIndex = -1; // maximum index of constrained parameter/s + protected double constraintTolerance = 1e-4; // tolerance in constraining parameter/s to a fixed value + protected ArrayList<Object> penalties = new ArrayList<Object>(); // 3 method index, + // number of single parameter constraints, + // then repeated for each constraint: + // penalty parameter index, + // below or above constraint flag, + // constraint boundary value + protected ArrayList<Object> sumPenalties = new ArrayList<Object>(); // constraint method index, + // number of multiple parameter constraints, + // then repeated for each constraint: + // number of parameters in summation + // penalty parameter indices, + // summation signs + // below or above constraint flag, + // constraint boundary value + protected int[] penaltyCheck = null; // = -1 values below the single constraint boundary not allowed + // = +1 values above the single constraint boundary not allowed + protected int[] sumPenaltyCheck = null; // = -1 values below the multiple constraint boundary not allowed + // = +1 values above the multiple constraint boundary not allowed + protected double penaltyWeight = 1.0e30; // weight for the penalty functions + protected int[] penaltyParam = null; // indices of paramaters subject to single parameter constraint + protected int[][] sumPenaltyParam = null; // indices of paramaters subject to multiple parameter constraint + protected double[][] sumPlusOrMinus = null; // valueall before each parameter in multiple parameter summation + protected int[] sumPenaltyNumber = null; // number of paramaters in each multiple parameter constraint + + protected double[] constraints = null; // single parameter constraint values + protected double[] sumConstraints = null; // multiple parameter constraint values + protected int constraintMethod = 0; // constraint method number + // =0: cliff to the power two (only method at present) + + protected boolean scaleFlag = true; // if true ordinate scale factor, Ao, included as unknown in fitting to special functions + // if false Ao set to unity (default value) or user provided value (in yScaleFactor) + protected double yScaleFactor = 1.0D; // y axis factor - set if scaleFlag (above) = false + protected int nMax = 3000; // Nelder and Mead simplex maximum number of iterations + protected int nIter = 0; // Nelder and Mead simplex number of iterations performed + protected int konvge = 3; // Nelder and Mead simplex number of restarts allowed + protected int kRestart = 0; // Nelder and Mead simplex number of restarts taken + protected double fMin = -1.0D; // Nelder and Mead simplex minimum value + protected double fTol = 1e-9; // Nelder and Mead simplex convergence tolerance + protected double rCoeff = 1.0D; // Nelder and Mead simplex reflection coefficient + protected double eCoeff = 2.0D; // Nelder and Mead simplex extension coefficient + protected double cCoeff = 0.5D; // Nelder and Mead simplex contraction coefficient + protected double[] startH = null; // Nelder and Mead simplex unscaled initial estimates + protected double[] stepH = null; // Nelder and Mead simplex unscaled initial step values + protected double[] startSH = null; // Nelder and Mead simplex scaled initial estimates + protected double[] stepSH = null; // Nelder and Mead simplex scaled initial step values + protected double dStep = 0.5D; // Nelder and Mead simplex default step value + protected double[][] grad = null; // Non-linear regression gradients + protected double delta = 1e-4; // Fractional step in numerical differentiation + protected boolean invertFlag=true; // Hessian Matrix ('linear' non-linear statistics) check + // true matrix successfully inverted, false inversion failed + protected boolean posVarFlag=true; // Hessian Matrix ('linear' non-linear statistics) check + // true - all variances are positive; false - at least one is negative + protected int minTest = 0; // Nelder and Mead minimum test + // = 0; tests simplex sd < fTol + // = 1; tests reduced chi suare or sum of squares < mean of abs(y values)*fTol + protected double simplexSd = 0.0D; // simplex standard deviation + protected boolean statFlag = true; // if true - statistical method called + // if false - no statistical analysis + protected boolean plotOpt = true; // if true - plot of calculated values is cubic spline interpolation between the calculated values + // if false - calculated values linked by straight lines (accomodates Poiwsson distribution plots) + protected boolean multipleY = false; // = true if y variable consists of more than set of data each needing a different calculation in RegressionFunction + // when set to true - the index of the y value is passed to the function in Regression function + + protected double[] values = null; // values entered into gaussianFixed + protected boolean[] fixed = null; // true if above values[i] is fixed, false if it is not + + protected boolean ignoreDofFcheck = false; // when set to true, the check on whether degrees of freedom are greater than zero is ignored + + protected boolean nFactorOption = false; // = true varaiance, covariance and standard deviation denominator = n + // = false varaiance, covariance and standard deviation denominator = n-1 + + + // HISTOGRAM CONSTRUCTION + // Tolerance used in including an upper point in last histogram bin when it is outside due to riunding erors + protected static double histTol = 1.0001D; + + //CONSRUCTORS + + // Default constructor - primarily facilitating the subclass ImpedSpecRegression + public Regression(){ + } + + + // Constructor with data with x as 2D array and weights provided + public Regression(double[][] xData, double[] yData, double[] weight){ + + int n=weight.length; + this.nData0 = yData.length; + weight = this.checkForZeroWeights(weight); + if(this.weightOpt)this.weightFlag = 1; + this.setDefaultValues(xData, yData, weight); + } + + // Constructor with data with x and y as 2D arrays and weights provided + public Regression(double[][] xxData, double[][] yyData, double[][] wWeight){ + this.multipleY = true; + int nY1 = yyData.length; + this.nYarrays = nY1; + int nY2 = yyData[0].length; + this.nData0 = nY2; + int nX1 = xxData.length; + int nX2 = xxData[0].length; + double[] yData = new double[nY1*nY2]; + double[] weight = new double[nY1*nY2]; + double[][] xData = new double[nY1*nY2][nX1]; + int ii=0; + for(int i=0; i<nY1; i++){ + int nY = yyData[i].length; + if(nY!=nY2)throw new IllegalArgumentException("multiple y arrays must be of the same length"); + int nX = xxData[i].length; + if(nY!=nX)throw new IllegalArgumentException("multiple y arrays must be of the same length as the x array length"); + for(int j=0; j<nY2; j++){ + yData[ii] = yyData[i][j]; + xData[ii][i] = xxData[i][j]; + weight[ii] = wWeight[i][j]; + ii++; + } + } + weight = this.checkForZeroWeights(weight); + if(this.weightOpt)this.weightFlag = 1; + this.setDefaultValues(xData, yData, weight); + } + + // Constructor with data with x as 1D array and weights provided + public Regression(double[] xxData, double[] yData, double[] weight){ + this.nData0 = yData.length; + int n = xxData.length; + int m = weight.length; + double[][] xData = new double[1][n]; + for(int i=0; i<n; i++){ + xData[0][i]=xxData[i]; + } + + weight = this.checkForZeroWeights(weight); + if(this.weightOpt)this.weightFlag = 1; + this.setDefaultValues(xData, yData, weight); + } + + // Constructor with data with x as 1D array and y as 2D array and weights provided + public Regression(double[] xxData, double[][] yyData, double[][] wWeight){ + + this.multipleY = true; + int nY1 = yyData.length; + this.nYarrays = nY1; + int nY2= yyData[0].length; + this.nData0 = nY2; + double[] yData = new double[nY1*nY2]; + double[] weight = new double[nY1*nY2]; + int ii=0; + for(int i=0; i<nY1; i++){ + int nY = yyData[i].length; + if(nY!=nY2)throw new IllegalArgumentException("multiple y arrays must be of the same length"); + for(int j=0; j<nY2; j++){ + yData[ii] = yyData[i][j]; + weight[ii] = wWeight[i][j]; + ii++; + } + } + int n = xxData.length; + if(n!=nY2)throw new IllegalArgumentException("x and y data lengths must be the same"); + double[][] xData = new double[1][nY1*n]; + ii=0; + for(int j=0; j<nY1; j++){ + for(int i=0; i<n; i++){ + xData[0][ii]=xxData[i]; + ii++; + } + } + + weight = this.checkForZeroWeights(weight); + if(this.weightOpt)this.weightFlag = 1; + this.setDefaultValues(xData, yData, weight); + } + + // Constructor with data with x as 2D array and no weights provided + public Regression(double[][] xData, double[] yData){ + this.nData0 = yData.length; + int n = yData.length; + double[] weight = new double[n]; + + this.weightOpt=false; + this.weightFlag = 0; + for(int i=0; i<n; i++)weight[i]=1.0D; + + setDefaultValues(xData, yData, weight); + } + + // Constructor with data with x and y as 2D arrays and no weights provided + public Regression(double[][] xxData, double[][] yyData){ + this.multipleY = true; + int nY1 = yyData.length; + this.nYarrays = nY1; + int nY2 = yyData[0].length; + this.nData0 = nY2; + int nX1 = xxData.length; + int nX2 = xxData[0].length; + double[] yData = new double[nY1*nY2]; + if(nY1!=nX1)throw new IllegalArgumentException("Multiple xData and yData arrays of different overall dimensions not supported"); + double[][] xData = new double[1][nY1*nY2]; + int ii=0; + for(int i=0; i<nY1; i++){ + int nY = yyData[i].length; + if(nY!=nY2)throw new IllegalArgumentException("multiple y arrays must be of the same length"); + int nX = xxData[i].length; + if(nY!=nX)throw new IllegalArgumentException("multiple y arrays must be of the same length as the x array length"); + for(int j=0; j<nY2; j++){ + yData[ii] = yyData[i][j]; + xData[0][ii] = xxData[i][j]; + ii++; + } + } + + int n = yData.length; + double[] weight = new double[n]; + + this.weightOpt=false; + for(int i=0; i<n; i++)weight[i]=1.0D; + this.weightFlag = 0; + + setDefaultValues(xData, yData, weight); + } + + // Constructor with data with x as 1D array and no weights provided + public Regression(double[] xxData, double[] yData){ + this.nData0 = yData.length; + int n = xxData.length; + double[][] xData = new double[1][n]; + double[] weight = new double[n]; + + for(int i=0; i<n; i++)xData[0][i]=xxData[i]; + + this.weightOpt=false; + this.weightFlag = 0; + for(int i=0; i<n; i++)weight[i]=1.0D; + + setDefaultValues(xData, yData, weight); + } + + // Constructor with data with x as 1D array and y as a 2D array and no weights provided + public Regression(double[] xxData, double[][] yyData){ + this.multipleY = true; + int nY1 = yyData.length; + this.nYarrays = nY1; + int nY2= yyData[0].length; + this.nData0 = nY2; + double[] yData = new double[nY1*nY2]; + int ii=0; + for(int i=0; i<nY1; i++){ + int nY = yyData[i].length; + if(nY!=nY2)throw new IllegalArgumentException("multiple y arrays must be of the same length"); + for(int j=0; j<nY2; j++){ + yData[ii] = yyData[i][j]; + ii++; + } + } + + double[][] xData = new double[1][nY1*nY2]; + double[] weight = new double[nY1*nY2]; + + ii=0; + int n = xxData.length; + for(int j=0; j<nY1; j++){ + for(int i=0; i<n; i++){ + xData[0][ii]=xxData[i]; + weight[ii]=1.0D; + ii++; + } + } + this.weightOpt=false; + this.weightFlag = 0; + + setDefaultValues(xData, yData, weight); + } + + // Constructor with data as a single array that has to be binned + // bin width and value of the low point of the first bin provided + public Regression(double[] xxData, double binWidth, double binZero){ + double[][] data = Regression.histogramBins(xxData, binWidth, binZero); + int n = data[0].length; + this.nData0 = n; + double[][] xData = new double[1][n]; + double[] yData = new double[n]; + double[] weight = new double[n]; + for(int i=0; i<n; i++){ + xData[0][i]=data[0][i]; + yData[i]=data[1][i]; + } + boolean flag = setTrueFreqWeights(yData, weight); + if(flag){ + this.trueFreq=true; + this.weightOpt=true; + this.weightFlag = 1; + } + else{ + this.trueFreq=false; + this.weightOpt=false; + this.weightFlag = 0; + } + setDefaultValues(xData, yData, weight); + } + + // Constructor with data as a single array that has to be binned + // bin width provided + public Regression(double[] xxData, double binWidth){ + double[][] data = Regression.histogramBins(xxData, binWidth); + int n = data[0].length; + this.nData0 = n; + double[][] xData = new double[1][n]; + double[] yData = new double[n]; + double[] weight = new double[n]; + for(int i=0; i<n; i++){ + xData[0][i]=data[0][i]; + yData[i]=data[1][i]; + } + boolean flag = setTrueFreqWeights(yData, weight); + if(flag){ + this.trueFreq=true; + this.weightOpt=true; + this.weightFlag = 1; + } + else{ + this.trueFreq=false; + this.weightOpt=false; + this.weightFlag = 0; + } + setDefaultValues(xData, yData, weight); + } + + // Check entered weights for zeros. + // If more than 40% are zero or less than zero, all weights replaced by unity + // If less than 40% are zero or less than zero, the zero or negative weights are replaced by the average of their nearest neighbours + protected double[] checkForZeroWeights(double[] weight){ + this.weightOpt=true; + int nZeros = 0; + int n=weight.length; + + for(int i=0; i<n; i++)if(weight[i]<=0.0)nZeros++; + double perCentZeros = 100.0*(double)nZeros/(double)n; + if(perCentZeros>40.0){ + System.out.println(perCentZeros + "% of the weights are zero or less; all weights set to 1.0"); + for(int i=0; i<n; i++)weight[i]=1.0D; + this.weightOpt = false; + } + else{ + if(perCentZeros>0.0D){ + for(int i=0; i<n; i++){ + if(weight[i]<=0.0){ + if(i==0){ + int ii=1; + boolean test = true; + while(test){ + if(weight[ii]>0.0D){ + double ww = weight[0]; + weight[0] = weight[ii]; + System.out.println("weight at point " + i + ", " + ww + ", replaced by "+ weight[i]); + test = false; + } + else{ + ii++; + } + } + } + if(i==(n-1)){ + int ii=n-2; + boolean test = true; + while(test){ + if(weight[ii]>0.0D){ + double ww = weight[i]; + weight[i] = weight[ii]; + System.out.println("weight at point " + i + ", " + ww + ", replaced by "+ weight[i]); + test = false; + } + else{ + ii--; + } + } + } + if(i>0 && i<(n-2)){ + double lower = 0.0; + double upper = 0.0; + int ii=i-1; + boolean test = true; + while(test){ + if(weight[ii]>0.0D){ + lower = weight[ii]; + test = false; + } + else{ + ii--; + if(ii==0)test = false; + } + } + ii=i+1; + test = true; + while(test){ + if(weight[ii]>0.0D){ + upper = weight[ii]; + test = false; + } + else{ + ii++; + if(ii==(n-1))test = false; + } + } + double ww = weight[i]; + if(lower==0.0){ + weight[i] = upper; + } + else{ + if(upper==0.0){ + weight[i] = lower; + } + else{ + weight[i] = (lower + upper)/2.0; + } + } + System.out.println("weight at point " + i + ", " + ww + ", replaced by "+ weight[i]); + } + } + } + } + } + return weight; + } + + // Enter data methods + // Enter data with x as 2D array and weights provided + public void enterData(double[][] xData, double[] yData, double[] weight){ + + int n=weight.length; + this.nData0 = yData.length; + this.weightOpt=true; + weight = this.checkForZeroWeights(weight); + if(this.weightOpt)this.weightFlag = 1; + this.setDefaultValues(xData, yData, weight); + } + + // Enter data with x and y as 2D arrays and weights provided + public void enterData(double[][] xxData, double[][] yyData, double[][] wWeight){ + this.multipleY = true; + int nY1 = yyData.length; + this.nYarrays = nY1; + int nY2 = yyData[0].length; + this.nData0 = nY2; + int nX1 = xxData.length; + int nX2 = xxData[0].length; + double[] yData = new double[nY1*nY2]; + double[] weight = new double[nY1*nY2]; + double[][] xData = new double[nY1*nY2][nX1]; + int ii=0; + for(int i=0; i<nY1; i++){ + int nY = yyData[i].length; + if(nY!=nY2)throw new IllegalArgumentException("multiple y arrays must be of the same length"); + int nX = xxData[i].length; + if(nY!=nX)throw new IllegalArgumentException("multiple y arrays must be of the same length as the x array length"); + for(int j=0; j<nY2; j++){ + yData[ii] = yyData[i][j]; + xData[ii][i] = xxData[i][j]; + weight[ii] = wWeight[i][j]; + ii++; + } + } + + weight = this.checkForZeroWeights(weight); + if(this.weightOpt)this.weightFlag = 1; + this.setDefaultValues(xData, yData, weight); + } + + // Enter data with x as 1D array and weights provided + public void enterData(double[] xxData, double[] yData, double[] weight){ + this.nData0 = yData.length; + int n = xxData.length; + int m = weight.length; + double[][] xData = new double[1][n]; + for(int i=0; i<n; i++){ + xData[0][i]=xxData[i]; + } + + weight = this.checkForZeroWeights(weight); + if(this.weightOpt)this.weightFlag = 1; + this.setDefaultValues(xData, yData, weight); + } + + // Enter data with x as 1D array and y as 2D array and weights provided + public void enterData(double[] xxData, double[][] yyData, double[][] wWeight){ + + this.multipleY = true; + int nY1 = yyData.length; + this.nYarrays = nY1; + int nY2= yyData[0].length; + this.nData0 = nY2; + double[] yData = new double[nY1*nY2]; + double[] weight = new double[nY1*nY2]; + int ii=0; + for(int i=0; i<nY1; i++){ + int nY = yyData[i].length; + if(nY!=nY2)throw new IllegalArgumentException("multiple y arrays must be of the same length"); + for(int j=0; j<nY2; j++){ + yData[ii] = yyData[i][j]; + weight[ii] = wWeight[i][j]; + ii++; + } + } + int n = xxData.length; + if(n!=nY2)throw new IllegalArgumentException("x and y data lengths must be the same"); + double[][] xData = new double[1][nY1*n]; + ii=0; + for(int j=0; j<nY1; j++){ + for(int i=0; i<n; i++){ + xData[0][ii]=xxData[i]; + ii++; + } + } + + weight = this.checkForZeroWeights(weight); + if(this.weightOpt)this.weightFlag = 1; + this.setDefaultValues(xData, yData, weight); + } + + // Enter data with x as 2D array and no weights provided + public void enterData(double[][] xData, double[] yData){ + this.nData0 = yData.length; + int n = yData.length; + double[] weight = new double[n]; + + this.weightOpt=false; + for(int i=0; i<n; i++)weight[i]=1.0D; + this.weightFlag = 0; + setDefaultValues(xData, yData, weight); + } + + // Enter data with x and y as 2D arrays and no weights provided + public void enterData(double[][] xxData, double[][] yyData){ + this.multipleY = true; + int nY1 = yyData.length; + this.nYarrays = nY1; + int nY2 = yyData[0].length; + this.nData0 = nY2; + int nX1 = xxData.length; + int nX2 = xxData[0].length; + double[] yData = new double[nY1*nY2]; + double[][] xData = new double[nY1*nY2][nX1]; + int ii=0; + for(int i=0; i<nY1; i++){ + int nY = yyData[i].length; + if(nY!=nY2)throw new IllegalArgumentException("multiple y arrays must be of the same length"); + int nX = xxData[i].length; + if(nY!=nX)throw new IllegalArgumentException("multiple y arrays must be of the same length as the x array length"); + for(int j=0; j<nY2; j++){ + yData[ii] = yyData[i][j]; + xData[ii][i] = xxData[i][j]; + ii++; + } + } + + int n = yData.length; + double[] weight = new double[n]; + + this.weightOpt=false; + for(int i=0; i<n; i++)weight[i]=1.0D; + this.weightFlag = 0; + + setDefaultValues(xData, yData, weight); + } + + // Enter data with x as 1D array and no weights provided + public void enterData(double[] xxData, double[] yData){ + this.nData0 = yData.length; + int n = xxData.length; + double[][] xData = new double[1][n]; + double[] weight = new double[n]; + + for(int i=0; i<n; i++)xData[0][i]=xxData[i]; + + this.weightOpt=false; + for(int i=0; i<n; i++)weight[i]=1.0D; + this.weightFlag = 0; + + setDefaultValues(xData, yData, weight); + } + + // Enter data with x as 1D array and y as a 2D array and no weights provided + public void enterData(double[] xxData, double[][] yyData){ + this.multipleY = true; + int nY1 = yyData.length; + this.nYarrays = nY1; + int nY2= yyData[0].length; + this.nData0 = nY2; + double[] yData = new double[nY1*nY2]; + int ii=0; + for(int i=0; i<nY1; i++){ + int nY = yyData[i].length; + if(nY!=nY2)throw new IllegalArgumentException("multiple y arrays must be of the same length"); + for(int j=0; j<nY2; j++){ + yData[ii] = yyData[i][j]; + ii++; + } + } + + double[][] xData = new double[1][nY1*nY2]; + double[] weight = new double[nY1*nY2]; + + ii=0; + int n = xxData.length; + for(int j=0; j<nY1; j++){ + for(int i=0; i<n; i++){ + xData[0][ii]=xxData[i]; + weight[ii]=1.0D; + ii++; + } + } + this.weightOpt=false; + this.weightFlag = 0; + + this.setDefaultValues(xData, yData, weight); + } + + // Enter data as a single array that has to be binned + // bin width and value of the low point of the first bin provided + public void enterData(double[] xxData, double binWidth, double binZero){ + double[][] data = Regression.histogramBins(xxData, binWidth, binZero); + int n = data[0].length; + this.nData0 = n; + double[][] xData = new double[1][n]; + double[] yData = new double[n]; + double[] weight = new double[n]; + for(int i=0; i<n; i++){ + xData[0][i]=data[0][i]; + yData[i]=data[1][i]; + } + boolean flag = setTrueFreqWeights(yData, weight); + if(flag){ + this.trueFreq=true; + this.weightOpt=true; + this.weightFlag = 1; + } + else{ + this.trueFreq=false; + this.weightOpt=false; + this.weightFlag = 0; + } + setDefaultValues(xData, yData, weight); + } + + // Enter data as a single array that has to be binned + // bin width provided + public void enterData(double[] xxData, double binWidth){ + double[][] data = Regression.histogramBins(xxData, binWidth); + int n = data[0].length; + this.nData0 = n; + double[][] xData = new double[1][n]; + double[] yData = new double[n]; + double[] weight = new double[n]; + for(int i=0; i<n; i++){ + xData[0][i]=data[0][i]; + yData[i]=data[1][i]; + } + boolean flag = setTrueFreqWeights(yData, weight); + if(flag){ + this.trueFreq=true; + this.weightOpt=true; + this.weightFlag = 0; + } + else{ + this.trueFreq=false; + this.weightOpt=false; + this.weightFlag = 0; + } + setDefaultValues(xData, yData, weight); + } + + + protected static boolean setTrueFreqWeights(double[] yData, double[] weight){ + int nData=yData.length; + boolean flag = true; + boolean unityWeight=false; + + // Set all weights to square root of frequency of occurence + for(int ii=0; ii<nData; ii++){ + weight[ii]=Math.sqrt(Math.abs(yData[ii])); + } + + // Check for zero weights and take average of neighbours as weight if it is zero + for(int ii=0; ii<nData; ii++){ + double last = 0.0D; + double next = 0.0D; + if(weight[ii]==0){ + // find previous non-zero value + boolean testLast = true; + int iLast = ii - 1; + while(testLast){ + if(iLast<0){ + testLast = false; + } + else{ + if(weight[iLast]==0.0D){ + iLast--; + } + else{ + last = weight[iLast]; + testLast = false; + } + } + } + + // find next non-zero value + boolean testNext = true; + int iNext = ii + 1; + while(testNext){ + if(iNext>=nData){ + testNext = false; + } + else{ + if(weight[iNext]==0.0D){ + iNext++; + } + else{ + next = weight[iNext]; + testNext = false; + } + } + } + + // Take average + weight[ii]=(last + next)/2.0D; + } + } + return flag; + } + + // Set data and default values + protected void setDefaultValues(double[][] xData, double[] yData, double[] weight){ + this.nData = yData.length; + this.nXarrays = xData.length; + this.nTerms = this.nXarrays; + this.yData = new double[nData]; + this.yCalc = new double[nData]; + this.weight = new double[nData]; + this.residual = new double[nData]; + this.residualW = new double[nData]; + this.xData = new double[nXarrays][nData]; + int n=weight.length; + if(n!=this.nData)throw new IllegalArgumentException("The weight and the y data lengths do not agree"); + for(int i=0; i<this.nData; i++){ + this.yData[i]=yData[i]; + this.weight[i]=weight[i]; + } + for(int j=0; j<this.nXarrays; j++){ + n=xData[j].length; + if(n!=this.nData)throw new IllegalArgumentException("An x [" + j + "] length " + n + " and the y data length, " + this.nData + ", do not agree"); + for(int i=0; i<this.nData; i++){ + this.xData[j][i]=xData[j][i]; + } + } + } + + // Set standard deviation, variance and covariance denominators to n + public void setDenominatorToN(){ + this.nFactorOption = true; + Stat.setStaticDenominatorToN(); + } + + // Set standard deviation, variance and covariance denominators to n + public void setDenominatorToNminusOne(){ + this.nFactorOption = false; + Stat.setStaticDenominatorToNminusOne(); + } + + + // Supress printing of results + public void supressPrint(){ + this.supressPrint = true; + } + + // Supress plot of calculated versus experimental values + public void supressYYplot(){ + this.supressYYplot = true; + } + + // Supress convergence and chiSquare error messages + public void supressErrorMessages(){ + this.supressErrorMessages = true; + } + + // Ignore check on whether degrtees of freedom are greater than zero + public void ignoreDofFcheck(){ + this.ignoreDofFcheck = true; + } + + // Supress the statistical analysis + public void supressStats(){ + this.statFlag = false; + } + + // Reinstate statistical analysis + public void reinstateStats(){ + this.statFlag = true; + } + + // Reset the ordinate scale factor option + // true - Ao is unkown to be found by regression procedure + // false - Ao set to unity + public void setYscaleOption(boolean flag){ + this.scaleFlag=flag; + if(flag==false)this.yScaleFactor = 1.0D; + } + + // Reset the ordinate scale factor option + // true - Ao is unkown to be found by regression procedure + // false - Ao set to unity + // retained for backward compatibility + public void setYscale(boolean flag){ + this.scaleFlag=flag; + if(flag==false)this.yScaleFactor = 1.0D; + } + + // Reset the ordinate scale factor option + // true - Ao is unkown to be found by regression procedure + // false - Ao set to given value + public void setYscaleFactor(double scale){ + this.scaleFlag=false; + this.yScaleFactor = scale; + } + + // Get the ordinate scale factor option + // true - Ao is unkown + // false - Ao set to unity + public boolean getYscaleOption(){ + return this.scaleFlag; + } + + // Get the ordinate scale factor option + // true - Ao is unkown + // false - Ao set to unity + // retained to ensure backward compatibility + public boolean getYscale(){ + return this.scaleFlag; + } + + // Reset the true frequency test, trueFreq + // true if yData values are true frequencies, e.g. in a fit to Gaussian; false if not + // if true chiSquarePoisson (see above) is also calculated + public void setTrueFreq(boolean trFr){ + boolean trFrOld = this.trueFreq; + this.trueFreq = trFr; + if(trFr){ + boolean flag = setTrueFreqWeights(this.yData, this.weight); + if(flag){ + this.trueFreq=true; + this.weightOpt=true; + } + else{ + this.trueFreq=false; + this.weightOpt=false; + } + } + else{ + if(trFrOld){ + for(int i=0; i<this.weight.length; i++){ + weight[i]=1.0D; + } + this.weightOpt=false; + } + } + } + + // Get the true frequency test, trueFreq + public boolean getTrueFreq(){ + return this.trueFreq; + } + + // Reset the x axis legend + public void setXlegend(String legend){ + this.xLegend = legend; + this.legendCheck=true; + } + + // Reset the y axis legend + public void setYlegend(String legend){ + this.yLegend = legend; + this.legendCheck=true; + } + + // Set the title + public void setTitle(String title){ + this.graphTitle = title; + } + + // Multiple linear regression with intercept (including y = ax + b) + // y = a + b.x1 + c.x2 + d.x3 + . . . + public void linear(){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod = 0; + this.linNonLin = true; + this.nTerms = this.nXarrays+1; + this.degreesOfFreedom = this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + double[][] aa = new double[this.nTerms][this.nData]; + + for(int j=0; j<nData; j++)aa[0][j]=1.0D; + for(int i=1; i<nTerms; i++){ + for(int j=0; j<nData; j++){ + aa[i][j]=this.xData[i-1][j]; + } + } + this.best = new double[this.nTerms]; + this.bestSd = new double[this.nTerms]; + this.tValues = new double[this.nTerms]; + this.pValues = new double[this.nTerms]; + this.generalLinear(aa); + if(!this.ignoreDofFcheck)this.generalLinearStats(aa); + } + + // Multiple linear regression with intercept (including y = ax + b) + // plus plot and output file + // y = a + b.x1 + c.x2 + d.x3 + . . . + // legends provided + public void linearPlot(String xLegend, String yLegend){ + this.xLegend = xLegend; + this.yLegend = yLegend; + this.legendCheck = true; + this.linear(); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY(); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Multiple linear regression with intercept (including y = ax + b) + // plus plot and output file + // y = a + b.x1 + c.x2 + d.x3 + . . . + // no legends provided + public void linearPlot(){ + this.linear(); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY(); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Polynomial fitting + // y = a + b.x + c.x^2 + d.x^3 + . . . + public void polynomial(int deg){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + if(this.nXarrays>1)throw new IllegalArgumentException("This class will only perform a polynomial regression on a single x array"); + if(deg<1)throw new IllegalArgumentException("Polynomial degree must be greater than zero"); + this.lastMethod = 1; + this.linNonLin = true; + this.nTerms = deg+1; + this.degreesOfFreedom = this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + double[][] aa = new double[this.nTerms][this.nData]; + + for(int j=0; j<nData; j++)aa[0][j]=1.0D; + for(int j=0; j<nData; j++)aa[1][j]=this.xData[0][j]; + + for(int i=2; i<nTerms; i++){ + for(int j=0; j<nData; j++){ + aa[i][j]=Math.pow(this.xData[0][j],i); + } + } + this.best = new double[this.nTerms]; + this.bestSd = new double[this.nTerms]; + this.tValues = new double[this.nTerms]; + this.pValues = new double[this.nTerms]; + this.generalLinear(aa); + if(!this.ignoreDofFcheck)this.generalLinearStats(aa); + } + + + // Polynomial fitting plus plot and output file + // y = a + b.x + c.x^2 + d.x^3 + . . . + // legends provided + public void polynomialPlot(int n, String xLegend, String yLegend){ + this.xLegend = xLegend; + this.yLegend = yLegend; + this.legendCheck = true; + this.polynomial(n); + if(!this.supressPrint)this.print(); + int flag = this.plotXY(); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Polynomial fitting plus plot and output file + // y = a + b.x + c.x^2 + d.x^3 + . . . + // No legends provided + public void polynomialPlot(int n){ + this.polynomial(n); + if(!this.supressPrint)this.print(); + int flag = this.plotXY(); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Generalised linear regression + // y = a.f1(x) + b.f2(x) + c.f3(x) + . . . + public void linearGeneral(){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod = 2; + + this.linNonLin = true; + this.nTerms = this.nXarrays; + this.degreesOfFreedom = this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + this.best = new double[this.nTerms]; + this.bestSd = new double[this.nTerms]; + this.tValues = new double[this.nTerms]; + this.pValues = new double[this.nTerms]; + this.generalLinear(this.xData); + if(!this.ignoreDofFcheck)this.generalLinearStats(this.xData); + } + + // Generalised linear regression plus plot and output file + // y = a.f1(x) + b.f2(x) + c.f3(x) + . . . + // legends provided + public void linearGeneralPlot(String xLegend, String yLegend){ + this.xLegend = xLegend; + this.yLegend = yLegend; + this.legendCheck = true; + this.linearGeneral(); + if(!this.supressPrint)this.print(); + if(!this.supressYYplot)this.plotYY(); + } + + // Generalised linear regression plus plot and output file + // y = a.f1(x) + b.f2(x) + c.f3(x) + . . . + // No legends provided + public void linearGeneralPlot(){ + this.linearGeneral(); + if(!this.supressPrint)this.print(); + if(!this.supressYYplot)this.plotYY(); + } + + // Generalised linear regression (protected method called by linear(), linearGeneral() and polynomial()) + protected void generalLinear(double[][] xd){ + if(this.nData<=this.nTerms && !this.ignoreDofFcheck)throw new IllegalArgumentException("Number of unknown parameters is greater than or equal to the number of data points"); + double sde=0.0D, sum=0.0D, yCalctemp=0.0D; + double[][] a = new double[this.nTerms][this.nTerms]; + double[][] h = new double[this.nTerms][this.nTerms]; + double[]b = new double[this.nTerms]; + double[]coeff = new double[this.nTerms]; + + // set statistic arrays to NaN if df check ignored + if(this.ignoreDofFcheck){ + this.bestSd = new double[this.nTerms]; + this.pseudoSd = new double[this.nTerms]; + this.tValues = new double[this.nTerms]; + this.pValues = new double[this.nTerms]; + + this.covar = new double[this.nTerms][this.nTerms]; + this.corrCoeff = new double[this.nTerms][this.nTerms];; + for(int i=0; i<this.nTerms; i++){ + this.bestSd[i] = Double.NaN; + this.pseudoSd[i] = Double.NaN; + for(int j=0; j<this.nTerms; j++){ + this.covar[i][j] = Double.NaN; + this.corrCoeff[i][j] = Double.NaN; + } + } + } + + for (int i=0; i<nTerms; ++i){ + sum=0.0D ; + for (int j=0; j<nData; ++j){ + sum += this.yData[j]*xd[i][j]/Fmath.square(this.weight[j]); + } + b[i]=sum; + } + for (int i=0; i<nTerms; ++i){ + for (int j=0; j<nTerms; ++j){ + sum=0.0; + for (int k=0; k<nData; ++k){ + sum += xd[i][k]*xd[j][k]/Fmath.square(this.weight[k]); + } + a[j][i]=sum; + } + } + Matrix aa = new Matrix(a); + if(this.supressErrorMessages)aa.supressErrorMessage(); + coeff = aa.solveLinearSet(b); + + for(int i=0; i<this.nTerms; i++){ + this.best[i] = coeff[i]; + } + } + + // Generalised linear regression statistics (protected method called by linear(), linearGeneral() and polynomial()) + protected void generalLinearStats(double[][] xd){ + double sde=0.0D, sum=0.0D, yCalctemp=0.0D; + double[][] a = new double[this.nTerms][this.nTerms]; + double[][] h = new double[this.nTerms][this.nTerms]; + double[][] stat = new double[this.nTerms][this.nTerms]; + double[][] cov = new double[this.nTerms][this.nTerms]; + this.covar = new double[this.nTerms][this.nTerms]; + this.corrCoeff = new double[this.nTerms][this.nTerms]; + double[]coeffSd = new double[this.nTerms]; + double[]coeff = new double[this.nTerms]; + + for(int i=0; i<this.nTerms; i++){ + coeff[i] = best[i]; + } + + if(this.weightOpt)this.chiSquare=0.0D; + this.sumOfSquares=0.0D; + for (int i=0; i< nData; ++i){ + yCalctemp=0.0; + for (int j=0; j<nTerms; ++j){ + yCalctemp += coeff[j]*xd[j][i]; + } + this.yCalc[i] = yCalctemp; + yCalctemp -= this.yData[i]; + this.residual[i]=yCalctemp; + this.residualW[i]=yCalctemp/weight[i]; + if(weightOpt)this.chiSquare += Fmath.square(yCalctemp/this.weight[i]); + this.sumOfSquares += Fmath.square(yCalctemp); + } + if(this.weightOpt || this.trueFreq)this.reducedChiSquare = this.chiSquare/(this.degreesOfFreedom); + double varY = this.sumOfSquares/(this.degreesOfFreedom); + double sdY = Math.sqrt(varY); + + if(this.sumOfSquares==0.0D){ + for(int i=0; i<this.nTerms;i++){ + coeffSd[i]=0.0D; + for(int j=0; j<this.nTerms;j++){ + this.covar[i][j]=0.0D; + if(i==j){ + this.corrCoeff[i][j]=1.0D; + } + else{ + this.corrCoeff[i][j]=0.0D; + } + } + } + } + else{ + for (int i=0; i<this.nTerms; ++i){ + for (int j=0; j<this.nTerms; ++j){ + sum=0.0; + for (int k=0; k<this.nData; ++k){ + if (weightOpt){ + sde = weight[k]; + } + else{ + sde = sdY; + } + sum += xd[i][k]*xd[j][k]/Fmath.square(sde); + } + h[j][i]=sum; + } + } + Matrix hh = new Matrix(h); + if(this.supressErrorMessages)hh.supressErrorMessage(); + hh = hh.inverse(); + stat = hh.getArrayCopy(); + for (int j=0; j<nTerms; ++j){ + coeffSd[j] = Math.sqrt(stat[j][j]); + } + + for(int i=0; i<this.nTerms;i++){ + for(int j=0; j<this.nTerms;j++){ + this.covar[i][j]=stat[i][j]; + } + } + + for(int i=0; i<this.nTerms;i++){ + for(int j=0; j<this.nTerms;j++){ + if(i==j){ + this.corrCoeff[i][j] = 1.0D; + } + else{ + this.corrCoeff[i][j]=covar[i][j]/(coeffSd[i]*coeffSd[j]); + } + } + } + } + + for(int i=0; i<this.nTerms; i++){ + this.bestSd[i] = coeffSd[i]; + this.tValues[i] = this.best[i]/this.bestSd[i]; + double atv = Math.abs(this.tValues[i]); + this.pValues[i] = 1.0 - Stat.studentTcdf(-atv, atv, this.degreesOfFreedom); + } + + if(this.nXarrays==1 && nYarrays==1){ + this.sampleR = Stat.corrCoeff(this.xData[0], this.yData, this.weight); + this.sampleR2 = this.sampleR*this.sampleR; + this.adjustedR = this.sampleR; + this.adjustedR2 = this.sampleR2; + } + else{ + this.multCorrelCoeff(this.yData, this.yCalc, this.weight); + } + } + + + // Nelder and Mead Simplex Simplex Non-linear Regression + protected void nelderMead(Object regFun, double[] start, double[] step, double fTol, int nMax){ + boolean testContract=false; // test whether a simplex contraction has been performed + int np = start.length; // number of unknown parameters; + if(this.maxConstraintIndex>=np)throw new IllegalArgumentException("You have entered more constrained parameters ("+this.maxConstraintIndex+") than minimisation parameters (" + np + ")"); + this.nlrStatus = true; // -> false if convergence criterion not met + this.nTerms = np; // number of parameters whose best estimates are to be determined + int nnp = np+1; // number of simplex apices + this.lastSSnoConstraint=0.0D; // last sum of squares without a penalty constraint being applied + + if(this.scaleOpt<2)this.scale = new double[np]; // scaling factors + if(scaleOpt==2 && scale.length!=start.length)throw new IllegalArgumentException("scale array and initial estimate array are of different lengths"); + if(step.length!=start.length)throw new IllegalArgumentException("step array length " + step.length + " and initial estimate array length " + start.length + " are of different"); + + // check for zero step sizes + for(int i=0; i<np; i++)if(step[i]==0.0D)throw new IllegalArgumentException("step " + i+ " size is zero"); + + // set statistic arrays to NaN if df check ignored + if(this.ignoreDofFcheck){ + this.bestSd = new double[this.nTerms]; + this.pseudoSd = new double[this.nTerms]; + this.tValues = new double[this.nTerms]; + this.pValues = new double[this.nTerms]; + + this.covar = new double[this.nTerms][this.nTerms]; + this.corrCoeff = new double[this.nTerms][this.nTerms];; + for(int i=0; i<this.nTerms; i++){ + this.bestSd[i] = Double.NaN; + this.pseudoSd[i] = Double.NaN; + for(int j=0; j<this.nTerms; j++){ + this.covar[i][j] = Double.NaN; + this.corrCoeff[i][j] = Double.NaN; + } + } + } + + // set up arrays + this.startH = new double[np]; // holding array of unscaled initial start values + this.stepH = new double[np]; // Nelder and Mead unscaled initial step values + this.startSH = new double[np]; // holding array of scaled initial start values + this.stepSH = new double[np]; // Nelder and Mead scaled initial step values + double[]pmin = new double[np]; // Nelder and Mead Pmin + this.best = new double[np]; // best estimates array + this.bestSd = new double[np]; // sd of best estimates array + this.tValues = new double[np]; // t-value of best estimates array + this.pValues = new double[np]; // p-value of best estimates array + + double[][] pp = new double[nnp][nnp]; //Nelder and Mead P + double[] yy = new double[nnp]; //Nelder and Mead y + double[] pbar = new double[nnp]; //Nelder and Mead P with bar superscript + double[] pstar = new double[nnp]; //Nelder and Mead P* + double[] p2star = new double[nnp]; //Nelder and Mead P** + + // mean of abs values of yData (for testing for minimum) + double yabsmean=0.0D; + for(int i=0; i<this.nData; i++)yabsmean += Math.abs(yData[i]); + yabsmean /= this.nData; + + // Set any single parameter constraint parameters + if(this.penalty){ + Integer itemp = (Integer)this.penalties.get(1); + this.nConstraints = itemp.intValue(); + this.penaltyParam = new int[this.nConstraints]; + this.penaltyCheck = new int[this.nConstraints]; + this.constraints = new double[this.nConstraints]; + Double dtemp = null; + int j=2; + for(int i=0;i<this.nConstraints;i++){ + itemp = (Integer)this.penalties.get(j); + this.penaltyParam[i] = itemp.intValue(); + j++; + itemp = (Integer)this.penalties.get(j); + this.penaltyCheck[i] = itemp.intValue(); + j++; + dtemp = (Double)this.penalties.get(j); + this.constraints[i] = dtemp.doubleValue(); + j++; + } + } + + // Set any multiple parameter constraint parameters + if(this.sumPenalty){ + Integer itemp = (Integer)this.sumPenalties.get(1); + this.nSumConstraints = itemp.intValue(); + this.sumPenaltyParam = new int[this.nSumConstraints][]; + this.sumPlusOrMinus = new double[this.nSumConstraints][]; + this.sumPenaltyCheck = new int[this.nSumConstraints]; + this.sumPenaltyNumber = new int[this.nSumConstraints]; + this.sumConstraints = new double[this.nSumConstraints]; + int[] itempArray = null; + double[] dtempArray = null; + Double dtemp = null; + int j=2; + for(int i=0;i<this.nSumConstraints;i++){ + itemp = (Integer)this.sumPenalties.get(j); + this.sumPenaltyNumber[i] = itemp.intValue(); + j++; + itempArray = (int[])this.sumPenalties.get(j); + this.sumPenaltyParam[i] = itempArray; + j++; + dtempArray = (double[])this.sumPenalties.get(j); + this.sumPlusOrMinus[i] = dtempArray; + j++; + itemp = (Integer)this.sumPenalties.get(j); + this.sumPenaltyCheck[i] = itemp.intValue(); + j++; + dtemp = (Double)this.sumPenalties.get(j); + this.sumConstraints[i] = dtemp.doubleValue(); + j++; + } + } + + // Store unscaled start and step values + for(int i=0; i<np; i++){ + this.startH[i]=start[i]; + this.stepH[i]=step[i]; + } + + // scale initial estimates and step sizes + if(this.scaleOpt>0){ + boolean testzero=false; + for(int i=0; i<np; i++)if(start[i]==0.0D)testzero=true; + if(testzero){ + System.out.println("Neler and Mead Simplex: a start value of zero precludes scaling"); + System.out.println("Regression performed without scaling"); + this.scaleOpt=0; + } + } + switch(this.scaleOpt){ + case 0: for(int i=0; i<np; i++)scale[i]=1.0D; + break; + case 1: for(int i=0; i<np; i++){ + scale[i]=1.0/start[i]; + step[i]=step[i]/start[i]; + start[i]=1.0D; + } + break; + case 2: for(int i=0; i<np; i++){ + step[i]*=scale[i]; + start[i]*= scale[i]; + } + break; + } + + // set class member values + this.fTol=fTol; + this.nMax=nMax; + this.nIter=0; + for(int i=0; i<np; i++){ + this.startSH[i] = start[i]; + this.stepSH[i] = step[i]; + this.scale[i] = scale[i]; + } + + // initial simplex + double sho=0.0D; + for (int i=0; i<np; ++i){ + sho=start[i]; + pstar[i]=sho; + p2star[i]=sho; + pmin[i]=sho; + } + + int jcount=this.konvge; // count of number of restarts still available + + for (int i=0; i<np; ++i){ + pp[i][nnp-1]=start[i]; + } + yy[nnp-1]=this.sumSquares(regFun, start); + for (int j=0; j<np; ++j){ + start[j]=start[j]+step[j]; + + for (int i=0; i<np; ++i)pp[i][j]=start[i]; + yy[j]=this.sumSquares(regFun, start); + start[j]=start[j]-step[j]; + } + + // loop over allowed iterations + double ynewlo=0.0D; // current value lowest y + double ystar = 0.0D; // Nelder and Mead y* + double y2star = 0.0D; // Nelder and Mead y** + double ylo = 0.0D; // Nelder and Mead y(low) + double fMin; // function value at minimum + // variables used in calculating the variance of the simplex at a putative minimum + double curMin = 00D, sumnm = 0.0D, summnm = 0.0D, zn = 0.0D; + int ilo=0; // index of low apex + int ihi=0; // index of high apex + int ln=0; // counter for a check on low and high apices + boolean test = true; // test becomes false on reaching minimum + + while(test){ + // Determine h + ylo=yy[0]; + ynewlo=ylo; + ilo=0; + ihi=0; + for (int i=1; i<nnp; ++i){ + if (yy[i]<ylo){ + ylo=yy[i]; + ilo=i; + } + if (yy[i]>ynewlo){ + ynewlo=yy[i]; + ihi=i; + } + } + // Calculate pbar + for (int i=0; i<np; ++i){ + zn=0.0D; + for (int j=0; j<nnp; ++j){ + zn += pp[i][j]; + } + zn -= pp[i][ihi]; + pbar[i] = zn/np; + } + + // Calculate p=(1+alpha).pbar-alpha.ph {Reflection} + for (int i=0; i<np; ++i)pstar[i]=(1.0 + this.rCoeff)*pbar[i]-this.rCoeff*pp[i][ihi]; + + // Calculate y* + ystar=this.sumSquares(regFun, pstar); + + ++this.nIter; + + // check for y*<yi + if(ystar < ylo){ + // Form p**=(1+gamma).p*-gamma.pbar {Extension} + for (int i=0; i<np; ++i)p2star[i]=pstar[i]*(1.0D + this.eCoeff)-this.eCoeff*pbar[i]; + // Calculate y** + y2star=this.sumSquares(regFun, p2star); + ++this.nIter; + if(y2star < ylo){ + // Replace ph by p** + for (int i=0; i<np; ++i)pp[i][ihi] = p2star[i]; + yy[ihi] = y2star; + } + else{ + //Replace ph by p* + for (int i=0; i<np; ++i)pp[i][ihi]=pstar[i]; + yy[ihi]=ystar; + } + } + else{ + // Check y*>yi, i!=h + ln=0; + for (int i=0; i<nnp; ++i)if (i!=ihi && ystar > yy[i]) ++ln; + if (ln==np ){ + // y*>= all yi; Check if y*>yh + if(ystar<=yy[ihi]){ + // Replace ph by p* + for (int i=0; i<np; ++i)pp[i][ihi]=pstar[i]; + yy[ihi]=ystar; + } + // Calculate p** =beta.ph+(1-beta)pbar {Contraction} + for (int i=0; i<np; ++i)p2star[i]=this.cCoeff*pp[i][ihi] + (1.0 - this.cCoeff)*pbar[i]; + // Calculate y** + y2star=this.sumSquares(regFun, p2star); + ++this.nIter; + // Check if y**>yh + if(y2star>yy[ihi]){ + //Replace all pi by (pi+pl)/2 + + for (int j=0; j<nnp; ++j){ + for (int i=0; i<np; ++i){ + pp[i][j]=0.5*(pp[i][j] + pp[i][ilo]); + pmin[i]=pp[i][j]; + } + yy[j]=this.sumSquares(regFun, pmin); + } + this.nIter += nnp; + } + else{ + // Replace ph by p** + for (int i=0; i<np; ++i)pp[i][ihi] = p2star[i]; + yy[ihi] = y2star; + } + } + else{ + // replace ph by p* + for (int i=0; i<np; ++i)pp[i][ihi]=pstar[i]; + yy[ihi]=ystar; + } + } + + // test for convergence + // calculte sd of simplex and minimum point + sumnm=0.0; + ynewlo=yy[0]; + ilo=0; + for (int i=0; i<nnp; ++i){ + sumnm += yy[i]; + if(ynewlo>yy[i]){ + ynewlo=yy[i]; + ilo=i; + } + } + sumnm /= (double)(nnp); + summnm=0.0; + for (int i=0; i<nnp; ++i){ + zn=yy[i]-sumnm; + summnm += zn*zn; + } + curMin=Math.sqrt(summnm/np); + + // test simplex sd + switch(this.minTest){ + case 0: + if(curMin<fTol)test=false; + break; + case 1: + if(Math.sqrt(ynewlo/this.degreesOfFreedom)<yabsmean*fTol)test=false; + break; + } + this.sumOfSquares=ynewlo; + if(!test){ + // store best estimates + for (int i=0; i<np; ++i)pmin[i]=pp[i][ilo]; + yy[nnp-1]=ynewlo; + // store simplex sd + this.simplexSd = curMin; + // test for restart + --jcount; + if(jcount>0){ + test=true; + for (int j=0; j<np; ++j){ + pmin[j]=pmin[j]+step[j]; + for (int i=0; i<np; ++i)pp[i][j]=pmin[i]; + yy[j]=this.sumSquares(regFun, pmin); + pmin[j]=pmin[j]-step[j]; + } + } + } + + if(test && this.nIter>this.nMax){ + if(!this.supressErrorMessages){ + System.out.println("Maximum iteration number reached, in Regression.simplex(...)"); + System.out.println("without the convergence criterion being satisfied"); + System.out.println("Current parameter estimates and sum of squares values returned"); + } + this.nlrStatus = false; + // store current estimates + for (int i=0; i<np; ++i)pmin[i]=pp[i][ilo]; + yy[nnp-1]=ynewlo; + test=false; + } + + } + + for (int i=0; i<np; ++i){ + pmin[i] = pp[i][ilo]; + this.best[i] = pmin[i]/this.scale[i]; + this.scale[i]=1.0D; // unscale for statistical methods + } + this.fMin=ynewlo; + this.kRestart=this.konvge-jcount; + + if(statFlag){ + if(!this.ignoreDofFcheck)pseudoLinearStats(regFun); + } + else{ + for (int i=0; i<np; ++i){ + this.bestSd[i] = Double.NaN; + } + } + } + + // Nelder and Mead Simplex Simplex Non-linear Regression + public void simplex(RegressionFunction g, double[] start, double[] step, double fTol, int nMax){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplex2 should have been called"); + Object regFun = (Object)g; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, step, fTol, nMax); + } + + + // Nelder and Mead Simplex Simplex Non-linear Regression + // plus plot and output file + public void simplexPlot(RegressionFunction g, double[] start, double[] step, double fTol, int nMax){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplexPlot2 should have been called"); + Object regFun = (Object)g; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, step, fTol, nMax); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Nelder and Mead simplex + // Default maximum iterations + public void simplex(RegressionFunction g, double[] start, double[] step, double fTol){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplex2 should have been called"); + Object regFun = (Object)g; + int nMaxx = this.nMax; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, step, fTol, nMaxx); + } + + // Nelder and Mead Simplex Simplex Non-linear Regression + // plus plot and output file + // Default maximum iterations + public void simplexPlot(RegressionFunction g, double[] start, double[] step, double fTol){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplexPlot2 should have been called"); + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.simplex(g, start, step, fTol); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Nelder and Mead simplex + // Default tolerance + public void simplex(RegressionFunction g, double[] start, double[] step, int nMax){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplex2 should have been called"); + Object regFun = (Object)g; + double fToll = this.fTol; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, step, fToll, nMax); + } + + // Nelder and Mead Simplex Simplex Non-linear Regression + // plus plot and output file + // Default tolerance + public void simplexPlot(RegressionFunction g, double[] start, double[] step, int nMax){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplexPlot2 should have been called"); + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.simplex(g, start, step, nMax); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Nelder and Mead simplex + // Default tolerance + // Default maximum iterations + public void simplex(RegressionFunction g, double[] start, double[] step){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplex2 should have been called"); + Object regFun = (Object)g; + double fToll = this.fTol; + int nMaxx = this.nMax; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, step, fToll, nMaxx); + } + + // Nelder and Mead Simplex Simplex Non-linear Regression + // plus plot and output file + // Default tolerance + // Default maximum iterations + public void simplexPlot(RegressionFunction g, double[] start, double[] step){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplexPlot2 should have been called"); + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.simplex(g, start, step); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Nelder and Mead simplex + // Default step option - all step[i] = dStep + public void simplex(RegressionFunction g, double[] start, double fTol, int nMax){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplex2 should have been called"); + Object regFun = (Object)g; + int n=start.length; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, stepp, fTol, nMax); + } + + // Nelder and Mead Simplex Simplex Non-linear Regression + // plus plot and output file + // Default step option - all step[i] = dStep + public void simplexPlot(RegressionFunction g, double[] start, double fTol, int nMax){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplexPlot2 should have been called"); + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.simplex(g, start, fTol, nMax); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Nelder and Mead simplex + // Default maximum iterations + // Default step option - all step[i] = dStep + public void simplex(RegressionFunction g, double[] start, double fTol){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplex2 should have been called"); + Object regFun = (Object)g; + int n=start.length; + int nMaxx = this.nMax; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, stepp, fTol, nMaxx); + } + + // Nelder and Mead Simplex Simplex Non-linear Regression + // plus plot and output file + // Default maximum iterations + // Default step option - all step[i] = dStep + public void simplexPlot(RegressionFunction g, double[] start, double fTol){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplexPlot2 should have been called"); + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.simplex(g, start, fTol); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Nelder and Mead simplex + // Default tolerance + // Default step option - all step[i] = dStep + public void simplex(RegressionFunction g, double[] start, int nMax){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplex2 should have been called"); + Object regFun = (Object)g; + int n=start.length; + double fToll = this.fTol; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.lastMethod=3; + this.userSupplied = true; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, stepp, fToll, nMax); + } + + // Nelder and Mead Simplex Simplex Non-linear Regression + // plus plot and output file + // Default tolerance + // Default step option - all step[i] = dStep + public void simplexPlot(RegressionFunction g, double[] start, int nMax){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplexPlot2 should have been called"); + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.simplex(g, start, nMax); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Nelder and Mead simplex + // Default tolerance + // Default maximum iterations + // Default step option - all step[i] = dStep + public void simplex(RegressionFunction g, double[] start){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplex2 should have been called"); + Object regFun = (Object)g; + int n=start.length; + int nMaxx = this.nMax; + double fToll = this.fTol; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, stepp, fToll, nMaxx); + } + + // Nelder and Mead Simplex Simplex Non-linear Regression + // plus plot and output file + // Default tolerance + // Default maximum iterations + // Default step option - all step[i] = dStep + public void simplexPlot(RegressionFunction g, double[] start){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays\nsimplexPlot2 should have been called"); + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.simplex(g, start); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + + + // Nelder and Mead Simplex Simplex2 Non-linear Regression + public void simplex2(RegressionFunction2 g, double[] start, double[] step, double fTol, int nMax){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + Object regFun = (Object)g; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, step, fTol, nMax); + } + + + // Nelder and Mead Simplex Simplex2 Non-linear Regression + // plus plot and output file + public void simplexPlot2(RegressionFunction2 g, double[] start, double[] step, double fTol, int nMax){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + Object regFun = (Object)g; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, step, fTol, nMax); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY2(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Nelder and Mead simplex + // Default maximum iterations + public void simplex2(RegressionFunction2 g, double[] start, double[] step, double fTol){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + Object regFun = (Object)g; + int nMaxx = this.nMax; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, step, fTol, nMaxx); + } + + // Nelder and Mead Simplex Simplex2 Non-linear Regression + // plus plot and output file + // Default maximum iterations + public void simplexPlot2(RegressionFunction2 g, double[] start, double[] step, double fTol){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.simplex2(g, start, step, fTol); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY2(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Nelder and Mead simplex + // Default tolerance + public void simplex2(RegressionFunction2 g, double[] start, double[] step, int nMax){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + Object regFun = (Object)g; + double fToll = this.fTol; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, step, fToll, nMax); + } + + // Nelder and Mead Simplex Simplex2 Non-linear Regression + // plus plot and output file + // Default tolerance + public void simplexPlot2(RegressionFunction2 g, double[] start, double[] step, int nMax){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.simplex2(g, start, step, nMax); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY2(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Nelder and Mead simplex + // Default tolerance + // Default maximum iterations + public void simplex2(RegressionFunction2 g, double[] start, double[] step){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + Object regFun = (Object)g; + double fToll = this.fTol; + int nMaxx = this.nMax; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, step, fToll, nMaxx); + } + + // Nelder and Mead Simplex Simplex2 Non-linear Regression + // plus plot and output file + // Default tolerance + // Default maximum iterations + public void simplexPlot2(RegressionFunction2 g, double[] start, double[] step){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.simplex2(g, start, step); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY2(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Nelder and Mead simplex + // Default step option - all step[i] = dStep + public void simplex2(RegressionFunction2 g, double[] start, double fTol, int nMax){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + Object regFun = (Object)g; + int n=start.length; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, stepp, fTol, nMax); + } + + // Nelder and Mead Simplex Simplex2 Non-linear Regression + // plus plot and output file + // Default step option - all step[i] = dStep + public void simplexPlot2(RegressionFunction2 g, double[] start, double fTol, int nMax){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.simplex2(g, start, fTol, nMax); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY2(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Nelder and Mead simplex + // Default maximum iterations + // Default step option - all step[i] = dStep + public void simplex2(RegressionFunction2 g, double[] start, double fTol){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + Object regFun = (Object)g; + int n=start.length; + int nMaxx = this.nMax; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, stepp, fTol, nMaxx); + } + + // Nelder and Mead Simplex Simplex2 Non-linear Regression + // plus plot and output file + // Default maximum iterations + // Default step option - all step[i] = dStep + public void simplexPlot2(RegressionFunction2 g, double[] start, double fTol){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.simplex2(g, start, fTol); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY2(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Nelder and Mead simplex + // Default tolerance + // Default step option - all step[i] = dStep + public void simplex2(RegressionFunction2 g, double[] start, int nMax){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + Object regFun = (Object)g; + int n=start.length; + double fToll = this.fTol; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.lastMethod=3; + this.userSupplied = true; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, stepp, fToll, nMax); + } + + // Nelder and Mead Simplex Simplex2 Non-linear Regression + // plus plot and output file + // Default tolerance + // Default step option - all step[i] = dStep + public void simplexPlot2(RegressionFunction2 g, double[] start, int nMax){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.simplex2(g, start, nMax); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY2(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Nelder and Mead simplex + // Default tolerance + // Default maximum iterations + // Default step option - all step[i] = dStep + public void simplex2(RegressionFunction2 g, double[] start){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + Object regFun = (Object)g; + int n=start.length; + int nMaxx = this.nMax; + double fToll = this.fTol; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom = this.nData - start.length; + this.nelderMead(regFun, start, stepp, fToll, nMaxx); + } + + // Nelder and Mead Simplex Simplex2 Non-linear Regression + // plus plot and output file + // Default tolerance + // Default maximum iterations + // Default step option - all step[i] = dStep + public void simplexPlot2(RegressionFunction2 g, double[] start){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + this.lastMethod=3; + this.userSupplied = true; + this.linNonLin = false; + this.zeroCheck = false; + this.simplex2(g, start); + if(!this.supressPrint)this.print(); + int flag = 0; + if(this.xData.length<2)flag = this.plotXY2(g); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // Calculate the sum of squares of the residuals for non-linear regression + protected double sumSquares(Object regFun, double[] x){ + RegressionFunction g1 = null; + RegressionFunction2 g2 = null; + if(this.multipleY){ + g2 = (RegressionFunction2)regFun; + } + else{ + g1 = (RegressionFunction)regFun; + } + + double ss = -3.0D; + double[] param = new double[this.nTerms]; + double[] xd = new double[this.nXarrays]; + // rescale + for(int i=0; i<this.nTerms; i++)param[i]=x[i]/scale[i]; + + // single parameter penalty functions + double tempFunctVal = this.lastSSnoConstraint; + boolean test=true; + if(this.penalty){ + int k=0; + for(int i=0; i<this.nConstraints; i++){ + k = this.penaltyParam[i]; + switch(penaltyCheck[i]){ + case -1: if(param[k]<constraints[i]){ + ss = tempFunctVal + this.penaltyWeight*Fmath.square(constraints[i]-param[k]); + test=false; + } + break; + case 0: if(param[k]<constraints[i]*(1.0-this.constraintTolerance)){ + ss = tempFunctVal + this.penaltyWeight*Fmath.square(constraints[i]*(1.0-this.constraintTolerance)-param[k]); + test=false; + } + if(param[k]>constraints[i]*(1.0+this.constraintTolerance)){ + ss = tempFunctVal + this.penaltyWeight*Fmath.square(param[k]-constraints[i]*(1.0+this.constraintTolerance)); + test=false; + } + break; + case 1: if(param[k]>constraints[i]){ + ss = tempFunctVal + this.penaltyWeight*Fmath.square(param[k]-constraints[i]); + test=false; + } + break; + } + } + } + + // multiple parameter penalty functions + if(this.sumPenalty){ + int kk = 0; + double pSign = 0; + double sumPenaltySum = 0.0D; + for(int i=0; i<this.nSumConstraints; i++){ + for(int j=0; j<this.sumPenaltyNumber[i]; j++){ + kk = this.sumPenaltyParam[i][j]; + pSign = this.sumPlusOrMinus[i][j]; + sumPenaltySum += param[kk]*pSign; + } + switch(this.sumPenaltyCheck[i]){ + case -1: if(sumPenaltySum<sumConstraints[i]){ + ss = tempFunctVal + this.penaltyWeight*Fmath.square(sumConstraints[i]-sumPenaltySum); + test=false; + } + break; + case 0: if(sumPenaltySum<sumConstraints[i]*(1.0-this.constraintTolerance)){ + ss = tempFunctVal + this.penaltyWeight*Fmath.square(sumConstraints[i]*(1.0-this.constraintTolerance)-sumPenaltySum); + test=false; + } + if(sumPenaltySum>sumConstraints[i]*(1.0+this.constraintTolerance)){ + ss = tempFunctVal + this.penaltyWeight*Fmath.square(sumPenaltySum-sumConstraints[i]*(1.0+this.constraintTolerance)); + test=false; + } + break; + case 1: if(sumPenaltySum>sumConstraints[i]){ + ss = tempFunctVal + this.penaltyWeight*Fmath.square(sumPenaltySum-sumConstraints[i]); + test=false; + } + break; + } + } + } + + if(test){ + ss = 0.0D; + for(int i=0; i<this.nData; i++){ + for(int j=0; j<nXarrays; j++)xd[j]=this.xData[j][i]; + if(!this.multipleY){ + ss += Fmath.square((this.yData[i] - g1.function(param, xd))/this.weight[i]); + } + else{ + ss += Fmath.square((this.yData[i] - g2.function(param, xd, i))/this.weight[i]); + } + + } + this.lastSSnoConstraint = ss; + + } + + + return ss; + + } + + // add a single parameter constraint boundary for the non-linear regression + public void addConstraint(int paramIndex, int conDir, double constraint){ + this.penalty=true; + + // First element reserved for method number if other methods than 'cliff' are added later + if(this.penalties.isEmpty())this.penalties.add(new Integer(this.constraintMethod)); + + // add constraint + if(penalties.size()==1){ + this.penalties.add(new Integer(1)); + } + else{ + int nPC = ((Integer)this.penalties.get(1)).intValue(); + nPC++; + this.penalties.set(1, new Integer(nPC)); + } + this.penalties.add(new Integer(paramIndex)); + this.penalties.add(new Integer(conDir)); + this.penalties.add(new Double(constraint)); + if(paramIndex>this.maxConstraintIndex)this.maxConstraintIndex = paramIndex; + } + + // add a multiple parameter constraint boundary for the non-linear regression + public void addConstraint(int[] paramIndices, int[] plusOrMinus, int conDir, double constraint){ + ArrayMaths am = new ArrayMaths(plusOrMinus); + double[] dpom = am.getArray_as_double(); + addConstraint(paramIndices, dpom, conDir, constraint); + } + + + // add a multiple parameter constraint boundary for the non-linear regression + public void addConstraint(int[] paramIndices, double[] plusOrMinus, int conDir, double constraint){ + int nCon = paramIndices.length; + int nPorM = plusOrMinus.length; + if(nCon!=nPorM)throw new IllegalArgumentException("num of parameters, " + nCon + ", does not equal number of parameter signs, " + nPorM); + this.sumPenalty=true; + + // First element reserved for method number if other methods than 'cliff' are added later + if(this.sumPenalties.isEmpty())this.sumPenalties.add(new Integer(this.constraintMethod)); + + // add constraint + if(sumPenalties.size()==1){ + this.sumPenalties.add(new Integer(1)); + } + else{ + int nPC = ((Integer)this.sumPenalties.get(1)).intValue(); + nPC++; + this.sumPenalties.set(1, new Integer(nPC)); + } + this.sumPenalties.add(new Integer(nCon)); + this.sumPenalties.add(paramIndices); + this.sumPenalties.add(plusOrMinus); + this.sumPenalties.add(new Integer(conDir)); + this.sumPenalties.add(new Double(constraint)); + ArrayMaths am = new ArrayMaths(paramIndices); + int maxI = am.getMaximum_as_int(); + if(maxI>this.maxConstraintIndex)this.maxConstraintIndex = maxI; + } + + // remove all constraint boundaries for the non-linear regression + public void removeConstraints(){ + + // check if single parameter constraints already set + if(!this.penalties.isEmpty()){ + int m=this.penalties.size(); + + // remove single parameter constraints + for(int i=m-1; i>=0; i--){ + this.penalties.remove(i); + } + } + this.penalty = false; + this.nConstraints = 0; + + // check if mutiple parameter constraints already set + if(!this.sumPenalties.isEmpty()){ + int m=this.sumPenalties.size(); + + // remove multiple parameter constraints + for(int i=m-1; i>=0; i--){ + this.sumPenalties.remove(i); + } + } + this.sumPenalty = false; + this.nSumConstraints = 0; + this.maxConstraintIndex = -1; + } + + // Reset the tolerance used in a fixed value constraint + public void setConstraintTolerance(double tolerance){ + this.constraintTolerance = tolerance; + } + + // linear statistics applied to a non-linear regression + protected int pseudoLinearStats(Object regFun){ + double f1 = 0.0D, f2 = 0.0D, f3 = 0.0D, f4 = 0.0D; // intermdiate values in numerical differentiation + int flag = 0; // returned as 0 if method fully successful; + // negative if partially successful or unsuccessful: check posVarFlag and invertFlag + // -1 posVarFlag or invertFlag is false; + // -2 posVarFlag and invertFlag are false + int np = this.nTerms; + + double[] f = new double[np]; + double[] pmin = new double[np]; + double[] coeffSd = new double[np]; + double[] xd = new double[this.nXarrays]; + double[][]stat = new double[np][np]; + pseudoSd = new double[np]; + + Double temp = null; + + this.grad = new double[np][2]; + this.covar = new double[np][np]; + this.corrCoeff = new double[np][np]; + + // get best estimates + pmin = best.clone(); + + // gradient both sides of the minimum + double hold0 = 1.0D; + double hold1 = 1.0D; + for (int i=0;i<np; ++i){ + for (int k=0;k<np; ++k){ + f[k]=pmin[k]; + } + hold0=pmin[i]; + if(hold0==0.0D){ + hold0=this.stepH[i]; + this.zeroCheck=true; + } + f[i]=hold0*(1.0D - this.delta); + this.lastSSnoConstraint=this.sumOfSquares; + f1=sumSquares(regFun, f); + f[i]=hold0*(1.0 + this.delta); + this.lastSSnoConstraint=this.sumOfSquares; + f2=sumSquares(regFun, f); + this.grad[i][0]=(this.fMin-f1)/Math.abs(this.delta*hold0); + this.grad[i][1]=(f2-this.fMin)/Math.abs(this.delta*hold0); + } + + // second patial derivatives at the minimum + this.lastSSnoConstraint=this.sumOfSquares; + for (int i=0;i<np; ++i){ + for (int j=0;j<np; ++j){ + for (int k=0;k<np; ++k){ + f[k]=pmin[k]; + } + hold0=f[i]; + if(hold0==0.0D){ + hold0=this.stepH[i]; + this.zeroCheck=true; + } + f[i]=hold0*(1.0 + this.delta/2.0D); + hold0=f[j]; + if(hold0==0.0D){ + hold0=this.stepH[j]; + this.zeroCheck=true; + } + f[j]=hold0*(1.0 + this.delta/2.0D); + this.lastSSnoConstraint=this.sumOfSquares; + f1=sumSquares(regFun, f); + f[i]=pmin[i]; + f[j]=pmin[j]; + hold0=f[i]; + if(hold0==0.0D){ + hold0=this.stepH[i]; + this.zeroCheck=true; + } + f[i]=hold0*(1.0 - this.delta/2.0D); + hold0=f[j]; + if(hold0==0.0D){ + hold0=this.stepH[j]; + this.zeroCheck=true; + } + f[j]=hold0*(1.0 + this.delta/2.0D); + this.lastSSnoConstraint=this.sumOfSquares; + f2=sumSquares(regFun, f); + f[i]=pmin[i]; + f[j]=pmin[j]; + hold0=f[i]; + if(hold0==0.0D){ + hold0=this.stepH[i]; + this.zeroCheck=true; + } + f[i]=hold0*(1.0 + this.delta/2.0D); + hold0=f[j]; + if(hold0==0.0D){ + hold0=this.stepH[j]; + this.zeroCheck=true; + } + f[j]=hold0*(1.0 - this.delta/2.0D); + this.lastSSnoConstraint=this.sumOfSquares; + f3=sumSquares(regFun, f); + f[i]=pmin[i]; + f[j]=pmin[j]; + hold0=f[i]; + if(hold0==0.0D){ + hold0=this.stepH[i]; + this.zeroCheck=true; + } + f[i]=hold0*(1.0 - this.delta/2.0D); + hold0=f[j]; + if(hold0==0.0D){ + hold0=this.stepH[j]; + this.zeroCheck=true; + } + f[j]=hold0*(1.0 - this.delta/2.0D); + this.lastSSnoConstraint=this.sumOfSquares; + f4=sumSquares(regFun, f); + stat[i][j]=(f1-f2-f3+f4)/(this.delta*this.delta); + } + } + + double ss=0.0D; + double sc=0.0D; + for(int i=0; i<this.nData; i++){ + for(int j=0; j<nXarrays; j++)xd[j]=this.xData[j][i]; + if(this.multipleY){ + this.yCalc[i] = ((RegressionFunction2)regFun).function(pmin, xd, i); + } + else{ + this.yCalc[i] = ((RegressionFunction)regFun).function(pmin, xd); + } + this.residual[i] = this.yCalc[i]-this.yData[i]; + ss += Fmath.square(this.residual[i]); + this.residualW[i] = this.residual[i]/this.weight[i]; + sc += Fmath.square(this.residualW[i]); + } + this.sumOfSquares = ss; + double varY = ss/(this.nData-np); + double sdY = Math.sqrt(varY); + if(this.weightOpt || this.trueFreq){ + this.chiSquare=sc; + this.reducedChiSquare=sc/(this.nData-np); + } + + // calculate reduced sum of squares + double red=1.0D; + if(!this.weightOpt && !this.trueFreq)red=this.sumOfSquares/(this.nData-np); + + // calculate pseudo errors - reduced sum of squares over second partial derivative + for(int i=0; i<np; i++){ + pseudoSd[i] = (2.0D*this.delta*red*Math.abs(pmin[i]))/(grad[i][1]-grad[i][0]); + if(pseudoSd[i]>=0.0D){ + pseudoSd[i] = Math.sqrt(pseudoSd[i]); + } + else{ + pseudoSd[i] = Double.NaN; + } + } + + // calculate covariance matrix + if(np==1){ + hold0=pmin[0]; + if(hold0==0.0D)hold0=this.stepH[0]; + stat[0][0]=1.0D/stat[0][0]; + this.covar[0][0] = stat[0][0]*red*hold0*hold0; + if(covar[0][0]>=0.0D){ + coeffSd[0]=Math.sqrt(this.covar[0][0]); + corrCoeff[0][0]=1.0D; + } + else{ + coeffSd[0]=Double.NaN; + corrCoeff[0][0]=Double.NaN; + this.posVarFlag=false; + } + } + else{ + Matrix cov = new Matrix(stat); + if(this.supressErrorMessages)cov.supressErrorMessage(); + double determinant = cov.determinant(); + if(determinant==0){ + this.invertFlag=false; + } + else{ + cov = cov.inverse(); + this.invertFlag = cov.getMatrixCheck(); + } + if(this.invertFlag==false)flag--; + stat = cov.getArrayCopy(); + + this.posVarFlag=true; + if (this.invertFlag){ + for (int i=0; i<np; ++i){ + hold0=pmin[i]; + if(hold0==0.0D)hold0=this.stepH[i]; + for (int j=i; j<np;++j){ + hold1=pmin[j]; + if(hold1==0.0D)hold1=this.stepH[j]; + this.covar[i][j] = 2.0D*stat[i][j]*red*hold0*hold1; + this.covar[j][i] = this.covar[i][j]; + } + if(covar[i][i]>=0.0D){ + coeffSd[i]=Math.sqrt(this.covar[i][i]); + } + else{ + coeffSd[i]=Double.NaN; + this.posVarFlag=false; + } + } + + for (int i=0; i<np; ++i){ + for (int j=0; j<np; ++j){ + if((coeffSd[i]!= Double.NaN) && (coeffSd[j]!= Double.NaN)){ + this.corrCoeff[i][j] = this.covar[i][j]/(coeffSd[i]*coeffSd[j]); + } + else{ + this.corrCoeff[i][j]= Double.NaN; + } + } + } + } + else{ + for (int i=0; i<np; ++i){ + for (int j=0; j<np;++j){ + this.covar[i][j] = Double.NaN; + this.corrCoeff[i][j] = Double.NaN; + } + coeffSd[i]=Double.NaN; + } + } + } + if(this.posVarFlag==false)flag--; + + for(int i=0; i<this.nTerms; i++){ + this.bestSd[i] = coeffSd[i]; + this.tValues[i] = this.best[i]/this.bestSd[i]; + double atv = Math.abs(this.tValues[i]); + this.pValues[i] = 1.0 - Stat.studentTcdf(-atv, atv, this.degreesOfFreedom); + + } + + this.multCorrelCoeff(this.yData, this.yCalc, this.weight); + + return flag; + + } + + // Print the results of the regression + // File name provided + // prec = truncation precision + public void print(String filename, int prec){ + this.prec = prec; + this.print(filename); + } + + // Print the results of the regression + // No file name provided + // prec = truncation precision + public void print(int prec){ + this.prec = prec; + String filename="RegressionOutput.txt"; + this.print(filename); + } + + // Print the results of the regression + // File name provided + // default value for truncation precision + public void print(String filename){ + if(filename.indexOf('.')==-1)filename = filename+".txt"; + FileOutput fout = new FileOutput(filename, 'n'); + fout.dateAndTimeln(filename); + fout.println(this.graphTitle); + paraName = new String[this.nTerms]; + if(lastMethod==38)paraName = new String[3]; + if(weightOpt){ + fout.println("Weighted Least Squares Minimisation"); + } + else{ + fout.println("Unweighted Least Squares Minimisation"); + } + switch(this.lastMethod){ + case 0: fout.println("Linear Regression with intercept"); + fout.println("y = c[0] + c[1]*x1 + c[2]*x2 +c[3]*x3 + . . ."); + for(int i=0;i<this.nTerms;i++)this.paraName[i]="c["+i+"]"; + this.linearPrint(fout); + break; + case 1: fout.println("Polynomial (with degree = " + (nTerms-1) + ") Fitting Linear Regression"); + fout.println("y = c[0] + c[1]*x + c[2]*x^2 +c[3]*x^3 + . . ."); + for(int i=0;i<this.nTerms;i++)this.paraName[i]="c["+i+"]"; + this.linearPrint(fout); + break; + case 2: fout.println("Generalised linear regression"); + fout.println("y = c[0]*f1(x) + c[1]*f2(x) + c[2]*f3(x) + . . ."); + for(int i=0;i<this.nTerms;i++)this.paraName[i]="c["+i+"]"; + this.linearPrint(fout); + break; + case 3: fout.println("Nelder and Mead Simplex Non-linear Regression"); + fout.println("y = f(x1, x2, x3 . . ., c[0], c[1], c[2] . . ."); + fout.println("y is non-linear with respect to the c[i]"); + for(int i=0;i<this.nTerms;i++)this.paraName[i]="c["+i+"]"; + this.nonLinearPrint(fout); + break; + case 4: fout.println("Fitting to a Normal (Gaussian) distribution"); + fout.println("y = (yscale/(sd.sqrt(2.pi)).exp(0.5.square((x-mean)/sd))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="mean"; + paraName[1]="sd"; + if(this.scaleFlag)paraName[2]="y scale"; + this.nonLinearPrint(fout); + break; + case 5: fout.println("Fitting to a Lorentzian distribution"); + fout.println("y = (yscale/pi).(gamma/2)/((x-mean)^2+(gamma/2)^2)"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="mean"; + paraName[1]="gamma"; + if(this.scaleFlag)paraName[2]="y scale"; + this.nonLinearPrint(fout); + break; + case 6: fout.println("Fitting to a Poisson distribution"); + fout.println("y = yscale.mu^k.exp(-mu)/mu!"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="mean"; + if(this.scaleFlag)paraName[1]="y scale"; + this.nonLinearPrint(fout); + break; + case 7: fout.println("Fitting to a Two Parameter Minimum Order Statistic Gumbel [Type 1 Extreme Value] Distribution"); + fout.println("y = (yscale/sigma)*exp((x - mu)/sigma))*exp(-exp((x-mu)/sigma))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="mu"; + paraName[1]="sigma"; + if(this.scaleFlag)paraName[2]="y scale"; + this.nonLinearPrint(fout); + break; + case 8: fout.println("Fitting to a Two Parameter Maximum Order Statistic Gumbel [Type 1 Extreme Value] Distribution"); + fout.println("y = (yscale/sigma)*exp(-(x - mu)/sigma))*exp(-exp(-(x-mu)/sigma))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="mu"; + paraName[1]="sigma"; + if(this.scaleFlag)paraName[2]="y scale"; + this.nonLinearPrint(fout); + break; + case 9: fout.println("Fitting to a One Parameter Minimum Order Statistic Gumbel [Type 1 Extreme Value] Distribution"); + fout.println("y = (yscale)*exp(x/sigma))*exp(-exp(x/sigma))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="sigma"; + if(this.scaleFlag)paraName[1]="y scale"; + this.nonLinearPrint(fout); + break; + case 10: fout.println("Fitting to a One Parameter Maximum Order Statistic Gumbel [Type 1 Extreme Value] Distribution"); + fout.println("y = (yscale)*exp(-x/sigma))*exp(-exp(-x/sigma))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="sigma"; + if(this.scaleFlag)paraName[1]="y scale"; + this.nonLinearPrint(fout); + break; + case 11: fout.println("Fitting to a Standard Minimum Order Statistic Gumbel [Type 1 Extreme Value] Distribution"); + fout.println("y = (yscale)*exp(x))*exp(-exp(x))"); + fout.println("Linear regression used to fit y = yscale*z where z = exp(x))*exp(-exp(x)))"); + if(this.scaleFlag)paraName[0]="y scale"; + this.linearPrint(fout); + break; + case 12: fout.println("Fitting to a Standard Maximum Order Statistic Gumbel [Type 1 Extreme Value] Distribution"); + fout.println("y = (yscale)*exp(-x))*exp(-exp(-x))"); + fout.println("Linear regression used to fit y = yscale*z where z = exp(-x))*exp(-exp(-x)))"); + if(this.scaleFlag)paraName[0]="y scale"; + this.linearPrint(fout); + break; + case 13: fout.println("Fitting to a Three Parameter Frechet [Type 2 Extreme Value] Distribution"); + fout.println("y = yscale.(gamma/sigma)*((x - mu)/sigma)^(-gamma-1)*exp(-((x-mu)/sigma)^-gamma"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="mu"; + paraName[1]="sigma"; + paraName[2]="gamma"; + if(this.scaleFlag)paraName[3]="y scale"; + this.nonLinearPrint(fout); + break; + case 14: fout.println("Fitting to a Two parameter Frechet [Type2 Extreme Value] Distribution"); + fout.println("y = yscale.(gamma/sigma)*(x/sigma)^(-gamma-1)*exp(-(x/sigma)^-gamma"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="sigma"; + paraName[1]="gamma"; + if(this.scaleFlag)paraName[2]="y scale"; + this.nonLinearPrint(fout); + break; + case 15: fout.println("Fitting to a Standard Frechet [Type 2 Extreme Value] Distribution"); + fout.println("y = yscale.gamma*(x)^(-gamma-1)*exp(-(x)^-gamma"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="gamma"; + if(this.scaleFlag)paraName[1]="y scale"; + this.nonLinearPrint(fout); + break; + case 16: fout.println("Fitting to a Three parameter Weibull [Type 3 Extreme Value] Distribution"); + fout.println("y = yscale.(gamma/sigma)*((x - mu)/sigma)^(gamma-1)*exp(-((x-mu)/sigma)^gamma"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="mu"; + paraName[1]="sigma"; + paraName[2]="gamma"; + if(this.scaleFlag)paraName[3]="y scale"; + this.nonLinearPrint(fout); + break; + case 17: fout.println("Fitting to a Two parameter Weibull [Type 3 Extreme Value] Distribution"); + fout.println("y = yscale.(gamma/sigma)*(x/sigma)^(gamma-1)*exp(-(x/sigma)^gamma"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="sigma"; + paraName[1]="gamma"; + if(this.scaleFlag)paraName[2]="y scale"; + this.nonLinearPrint(fout); + break; + case 18: fout.println("Fitting to a Standard Weibull [Type 3 Extreme Value] Distribution"); + fout.println("y = yscale.gamma*(x)^(gamma-1)*exp(-(x)^gamma"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="gamma"; + if(this.scaleFlag)paraName[1]="y scale"; + this.nonLinearPrint(fout); + break; + case 19: fout.println("Fitting to a Two parameter Exponential Distribution"); + fout.println("y = (yscale/sigma)*exp(-(x-mu)/sigma)"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="mu"; + paraName[1]="sigma"; + if(this.scaleFlag)paraName[2]="y scale"; + this.nonLinearPrint(fout); + break; + case 20: fout.println("Fitting to a One parameter Exponential Distribution"); + fout.println("y = (yscale/sigma)*exp(-x/sigma)"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="sigma"; + if(this.scaleFlag)paraName[1]="y scale"; + this.nonLinearPrint(fout); + break; + case 21: fout.println("Fitting to a Standard Exponential Distribution"); + fout.println("y = yscale*exp(-x)"); + fout.println("Nelder and Mead Simplex used to fit the data"); + if(this.scaleFlag)paraName[0]="y scale"; + this.nonLinearPrint(fout); + break; + case 22: fout.println("Fitting to a Rayleigh Distribution"); + fout.println("y = (yscale/sigma)*(x/sigma)*exp(-0.5*(x/sigma)^2)"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="sigma"; + if(this.scaleFlag)paraName[1]="y scale"; + this.nonLinearPrint(fout); + break; + case 23: fout.println("Fitting to a Two Parameter Pareto Distribution"); + fout.println("y = yscale*(alpha*beta^alpha)/(x^(alpha+1))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="alpha"; + paraName[1]="beta"; + if(this.scaleFlag)paraName[2]="y scale"; + this.nonLinearPrint(fout); + break; + case 24: fout.println("Fitting to a One Parameter Pareto Distribution"); + fout.println("y = yscale*(alpha)/(x^(alpha+1))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="alpha"; + if(this.scaleFlag)paraName[1]="y scale"; + this.nonLinearPrint(fout); + break; + case 25: fout.println("Fitting to a Sigmoidal Threshold Function"); + fout.println("y = yscale/(1 + exp(-slopeTerm(x - theta)))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="slope term"; + paraName[1]="theta"; + if(this.scaleFlag)paraName[2]="y scale"; + this.nonLinearPrint(fout); + break; + case 26: fout.println("Fitting to a Rectangular Hyperbola"); + fout.println("y = yscale.x/(theta + x)"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="theta"; + if(this.scaleFlag)paraName[1]="y scale"; + this.nonLinearPrint(fout); + break; + case 27: fout.println("Fitting to a Scaled Heaviside Step Function"); + fout.println("y = yscale.H(x - theta)"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="theta"; + if(this.scaleFlag)paraName[1]="y scale"; + this.nonLinearPrint(fout); + break; + case 28: fout.println("Fitting to a Hill/Sips Sigmoid"); + fout.println("y = yscale.x^n/(theta^n + x^n)"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="theta"; + paraName[1]="n"; + if(this.scaleFlag)paraName[2]="y scale"; + this.nonLinearPrint(fout); + break; + case 29: fout.println("Fitting to a Shifted Pareto Distribution"); + fout.println("y = yscale*(alpha*beta^alpha)/((x-theta)^(alpha+1))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="alpha"; + paraName[1]="beta"; + paraName[2]="theta"; + if(this.scaleFlag)paraName[3]="y scale"; + this.nonLinearPrint(fout); + break; + case 30: fout.println("Fitting to a Logistic distribution"); + fout.println("y = yscale*exp(-(x-mu)/beta)/(beta*(1 + exp(-(x-mu)/beta))^2"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="mu"; + paraName[1]="beta"; + if(this.scaleFlag)paraName[2]="y scale"; + this.nonLinearPrint(fout); + break; + case 31: fout.println("Fitting to a Beta distribution - [0, 1] interval"); + fout.println("y = yscale*x^(alpha-1)*(1-x)^(beta-1)/B(alpha, beta)"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="alpha"; + paraName[1]="beta"; + if(this.scaleFlag)paraName[2]="y scale"; + this.nonLinearPrint(fout); + break; + case 32: fout.println("Fitting to a Beta distribution - [min, max] interval"); + fout.println("y = yscale*(x-min)^(alpha-1)*(max-x)^(beta-1)/(B(alpha, beta)*(max-min)^(alpha+beta-1)"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="alpha"; + paraName[1]="beta"; + paraName[2]="min"; + paraName[3]="max"; + if(this.scaleFlag)paraName[4]="y scale"; + this.nonLinearPrint(fout); + break; + case 33: fout.println("Fitting to a Three Parameter Gamma distribution"); + fout.println("y = yscale*((x-mu)/beta)^(gamma-1)*exp(-(x-mu)/beta)/(beta*Gamma(gamma))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="mu"; + paraName[1]="beta"; + paraName[2]="gamma"; + if(this.scaleFlag)paraName[3]="y scale"; + this.nonLinearPrint(fout); + break; + case 34: fout.println("Fitting to a Standard Gamma distribution"); + fout.println("y = yscale*x^(gamma-1)*exp(-x)/Gamma(gamma)"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="gamma"; + if(this.scaleFlag)paraName[1]="y scale"; + this.nonLinearPrint(fout); + break; + case 35: fout.println("Fitting to an Erang distribution"); + fout.println("y = yscale*lambda^k*x^(k-1)*exp(-x*lambda)/(k-1)!"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="lambda"; + if(this.scaleFlag)paraName[1]="y scale"; + this.nonLinearPrint(fout); + break; + case 36: fout.println("Fitting to a two parameter log-normal distribution"); + fout.println("y = (yscale/(x.sigma.sqrt(2.pi)).exp(0.5.square((log(x)-muu)/sigma))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="mu"; + paraName[1]="sigma"; + if(this.scaleFlag)paraName[2]="y scale"; + this.nonLinearPrint(fout); + break; + case 37: fout.println("Fitting to a three parameter log-normal distribution"); + fout.println("y = (yscale/((x-alpha).beta.sqrt(2.pi)).exp(0.5.square((log(x-alpha)/gamma)/beta))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="alpha"; + paraName[1]="beta"; + paraName[2]="gamma"; + if(this.scaleFlag)paraName[3]="y scale"; + this.nonLinearPrint(fout); + break; + case 38: fout.println("Fitting to a Normal (Gaussian) distribution with fixed parameters"); + fout.println("y = (yscale/(sd.sqrt(2.pi)).exp(0.5.square((x-mean)/sd))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="mean"; + paraName[1]="sd"; + paraName[2]="y scale"; + this.nonLinearPrint(fout); + break; + case 39: fout.println("Fitting to a EC50 dose response curve"); + fout.println("y = bottom + (top - bottom)/(1 + (x/EC50)^HillSlope)"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="bottom"; + paraName[1]="top"; + paraName[2]="EC50"; + paraName[3]="Hill Slope"; + this.nonLinearPrint(fout); + break; + case 40: fout.println("Fitting to a LogEC50 dose response curve"); + fout.println("y = bottom + (top - bottom)/(1 + 10^((logEC50 - x).HillSlope))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="bottom"; + paraName[1]="top"; + paraName[2]="LogEC50"; + paraName[3]="Hill Slope"; + this.nonLinearPrint(fout); + break; + case 41: fout.println("Fitting to a EC50 dose response curve - bottom constrained to be zero or positive"); + fout.println("y = bottom + (top - bottom)/(1 + (x/EC50)^HillSlope)"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="bottom"; + paraName[1]="top"; + paraName[2]="EC50"; + paraName[3]="Hill Slope"; + this.nonLinearPrint(fout); + break; + case 42: fout.println("Fitting to a LogEC50 dose response curve - bottom constrained to be zero or positive"); + fout.println("y = bottom + (top - bottom)/(1 + 10^((logEC50 - x).HillSlope))"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="bottom"; + paraName[1]="top"; + paraName[2]="LogEC50"; + paraName[3]="Hill Slope"; + this.nonLinearPrint(fout); + break; + case 43: fout.println("Fitting to an exponential"); + fout.println("y = yscale.exp(A.x)"); + fout.println("Nelder and Mead Simplex used to fit the data"); + paraName[0]="A"; + if(this.scaleFlag)paraName[1]="y scale"; + this.nonLinearPrint(fout); + break; + case 44: fout.println("Fitting to multiple exponentials"); + fout.println("y = Sum[Ai.exp(Bi.x)], i=1 to n"); + fout.println("Nelder and Mead Simplex used to fit the data"); + for(int i=0;i<this.nTerms;i+=2){ + this.paraName[i]="A["+(i+1)+"]"; + this.paraName[i+1]="B["+(i+1)+"]"; + } + this.nonLinearPrint(fout); + break; + + default: throw new IllegalArgumentException("Method number (this.lastMethod) not found"); + + } + + fout.close(); + } + + // Print the results of the regression + // No file name provided + public void print(){ + String filename="RegressOutput.txt"; + this.print(filename); + } + + // protected method - print linear regression output + protected void linearPrint(FileOutput fout){ + + if(this.legendCheck){ + fout.println(); + fout.println("x1 = " + this.xLegend); + fout.println("y = " + this.yLegend); + } + + fout.println(); + fout.printtab(" ", this.field); + fout.printtab("Best", this.field); + fout.printtab("Error", this.field); + fout.printtab("Coefficient of", this.field); + fout.printtab("t-value ", this.field); + fout.println("p-value"); + + fout.printtab(" ", this.field); + fout.printtab("Estimate", this.field); + fout.printtab(" ", this.field); + fout.printtab("variation (%)", this.field); + fout.printtab("t ", this.field); + fout.println("P > |t|"); + + for(int i=0; i<this.nTerms; i++){ + fout.printtab(this.paraName[i], this.field); + fout.printtab(Fmath.truncate(best[i],this.prec), this.field); + fout.printtab(Fmath.truncate(bestSd[i],this.prec), this.field); + fout.printtab(Fmath.truncate(Math.abs(bestSd[i]*100.0D/best[i]),this.prec), this.field); + fout.printtab(Fmath.truncate(tValues[i],this.prec), this.field); + fout.println(Fmath.truncate((pValues[i]),this.prec)); + } + fout.println(); + + int ii=0; + if(this.lastMethod<2)ii=1; + for(int i=0; i<this.nXarrays; i++){ + fout.printtab("x"+String.valueOf(i+ii), this.field); + } + fout.printtab("y(expl)", this.field); + fout.printtab("y(calc)", this.field); + fout.printtab("weight", this.field); + fout.printtab("residual", this.field); + fout.println("residual"); + + for(int i=0; i<this.nXarrays; i++){ + fout.printtab(" ", this.field); + } + fout.printtab(" ", this.field); + fout.printtab(" ", this.field); + fout.printtab(" ", this.field); + fout.printtab("(unweighted)", this.field); + fout.println("(weighted)"); + + + for(int i=0; i<this.nData; i++){ + for(int j=0; j<this.nXarrays; j++){ + fout.printtab(Fmath.truncate(this.xData[j][i],this.prec), this.field); + } + fout.printtab(Fmath.truncate(this.yData[i],this.prec), this.field); + fout.printtab(Fmath.truncate(this.yCalc[i],this.prec), this.field); + fout.printtab(Fmath.truncate(this.weight[i],this.prec), this.field); + fout.printtab(Fmath.truncate(this.residual[i],this.prec), this.field); + fout.println(Fmath.truncate(this.residualW[i],this.prec)); + } + fout.println(); + fout.println("Sum of squares " + Fmath.truncate(this.sumOfSquares, this.prec)); + if(this.trueFreq){ + fout.printtab("Chi Square (Poissonian bins)"); + fout.println(Fmath.truncate(this.chiSquare,this.prec)); + fout.printtab("Reduced Chi Square (Poissonian bins)"); + fout.println(Fmath.truncate(this.reducedChiSquare,this.prec)); + fout.printtab("Chi Square (Poissonian bins) Probability"); + fout.println(Fmath.truncate((1.0D-Stat.chiSquareProb(this.chiSquare, this.nData-this.nXarrays)),this.prec)); + } + else{ + if(weightOpt){ + fout.printtab("Chi Square"); + fout.println(Fmath.truncate(this.chiSquare,this.prec)); + fout.printtab("Reduced Chi Square"); + fout.println(Fmath.truncate(this.reducedChiSquare,this.prec)); + fout.printtab("Chi Square Probability"); + fout.println(Fmath.truncate(this.getchiSquareProb(),this.prec)); + } + } + fout.println(" "); + fout.println("Correlation: x - y data"); + if(this.nXarrays>1){ + fout.printtab(this.weightWord[this.weightFlag] + "Multiple Sample Correlation Coefficient (R)"); + fout.println(Fmath.truncate(this.sampleR,this.prec)); + fout.printtab(this.weightWord[this.weightFlag] + "Multiple Sample Correlation Coefficient Squared (R^2)"); + fout.println(Fmath.truncate(this.sampleR2,this.prec)); + if(this.sampleR2<=1.0D){ + fout.printtab(this.weightWord[this.weightFlag] + "Multiple Correlation Coefficient F-test ratio"); + fout.println(Fmath.truncate(this.multipleF,this.prec)); + fout.printtab(this.weightWord[this.weightFlag] + "Multiple Correlation Coefficient F-test probability"); + fout.println(Fmath.truncate(Stat.fTestProb(this.multipleF, this.nXarrays-1, this.nData-this.nXarrays),this.prec)); + } + fout.printtab(this.weightWord[this.weightFlag] + "Adjusted Multiple Sample Correlation Coefficient (adjR)"); + fout.println(Fmath.truncate(this.adjustedR,this.prec)); + fout.printtab(this.weightWord[this.weightFlag] + "Adjusted Multiple Sample Correlation Coefficient Squared (adjR*adjR)"); + fout.println(Fmath.truncate(this.adjustedR2,this.prec)); + if(this.sampleR2<=1.0D){ + fout.printtab(this.weightWord[this.weightFlag] + "Adjusted Multiple Correlation Coefficient F-test ratio"); + fout.println(Fmath.truncate(this.adjustedF,this.prec)); + fout.printtab(this.weightWord[this.weightFlag] + "Adjusted Multiple Correlation Coefficient F-test probability"); + fout.println(Fmath.truncate(Stat.fTestProb(this.adjustedF, this.nXarrays-1, this.nData-this.nXarrays),this.prec)); + } + } + else{ + fout.printtab(this.weightWord[this.weightFlag] + "Linear Correlation Coefficient (R)"); + fout.println(Fmath.truncate(this.sampleR,this.prec)); + fout.printtab(this.weightWord[this.weightFlag] + "Linear Correlation Coefficient Squared (R^2)"); + fout.println(Fmath.truncate(this.sampleR2,this.prec)); + if(this.sampleR2<=1.0D){ + fout.printtab(this.weightWord[this.weightFlag] + "Linear Correlation Coefficient Probability"); + fout.println(Fmath.truncate(Stat.linearCorrCoeffProb(this.sampleR, this.nData-this.nTerms),this.prec)); + } + } + + fout.println(" "); + fout.println("Correlation: y(experimental) - y(calculated"); + fout.printtab(this.weightWord[this.weightFlag] + "Linear Correlation Coefficient"); + double ccyy = Stat.corrCoeff(this.yData, this.yCalc, this.weight); + + fout.println(Fmath.truncate(ccyy, this.prec)); + fout.printtab(this.weightWord[this.weightFlag] + "Linear Correlation Coefficient Probability"); + fout.println(Fmath.truncate(Stat.linearCorrCoeffProb(ccyy, this.nData-1),this.prec)); + + + fout.println(" "); + fout.printtab("Degrees of freedom"); + fout.println(this.nData - this.nTerms); + fout.printtab("Number of data points"); + fout.println(this.nData); + fout.printtab("Number of estimated paramaters"); + fout.println(this.nTerms); + + fout.println(); + if(this.chiSquare!=0.0D){ + fout.println("Correlation coefficients"); + fout.printtab(" ", this.field); + for(int i=0; i<this.nTerms;i++){ + fout.printtab(paraName[i], this.field); + } + fout.println(); + + for(int j=0; j<this.nTerms;j++){ + fout.printtab(paraName[j], this.field); + for(int i=0; i<this.nTerms;i++){ + fout.printtab(Fmath.truncate(this.corrCoeff[i][j], this.prec), this.field); + } + fout.println(); + } + } + + fout.println(); + fout.println("End of file"); + + fout.close(); + } + + // protected method - print non-linear regression output + protected void nonLinearPrint(FileOutput fout){ + if(this.userSupplied){ + fout.println(); + fout.println("Initial estimates were supplied by the user"); + } + else{ + fout.println("Initial estimates were calculated internally"); + } + + switch(this.scaleOpt){ + case 1: fout.println(); + fout.println("Initial estimates were scaled to unity within the regression"); + break; + case 2: fout.println(); + fout.println("Initial estimates were scaled with user supplied scaling factors within the regression"); + break; + } + + if(this.legendCheck){ + fout.println(); + fout.println("x1 = " + this.xLegend); + fout.println("y = " + this.yLegend); + } + + fout.println(); + if(!this.nlrStatus){ + fout.println("Convergence criterion was not satisfied"); + fout.println("The following results are, or a derived from, the current estimates on exiting the regression method"); + fout.println(); + } + + fout.println("Estimated parameters"); + fout.println("The statistics are obtained assuming that the model behaves as a linear model about the minimum."); + fout.println("The Hessian matrix is calculated as the numerically derived second derivatives of chi square with respect to all pairs of parameters."); + if(this.zeroCheck)fout.println("The best estimate/s equal to zero were replaced by the step size in the numerical differentiation!!!"); + fout.println("Consequentlty treat the statistics with great caution"); + if(!this.posVarFlag){ + fout.println("Covariance matrix contains at least one negative diagonal element"); + fout.println(" - all variances are dubious"); + fout.println(" - may not be at a minimum"); + } + if(!this.invertFlag){ + fout.println("Hessian matrix is singular"); + fout.println(" - variances cannot be calculated"); + fout.println(" - may not be at a minimum"); + } + + fout.println(" "); + if(!this.scaleFlag){ + fout.println("The ordinate scaling factor [yscale, Ao] has been set equal to " + this.yScaleFactor); + fout.println(" "); + } + if(lastMethod==35){ + fout.println("The integer rate parameter, k, was varied in unit steps to obtain a minimum sum of squares"); + fout.println("This value of k was " + this.kayValue); + fout.println(" "); + } + + fout.printtab(" ", this.field); + if(this.invertFlag){ + fout.printtab("Best", this.field); + fout.printtab("Estimate of", this.field); + fout.printtab("Coefficient", this.field); + fout.printtab("t-value", this.field); + fout.println("p-value"); + } + else{ + fout.println("Best"); + } + + if(this.invertFlag){ + fout.printtab(" ", this.field); + fout.printtab("estimate", this.field); + fout.printtab("the error", this.field); + fout.printtab("of", this.field); + fout.printtab("t", this.field); + fout.println("P > |t|"); + } + else{ + fout.printtab(" ", this.field); + fout.println("estimate"); + } + + if(this.invertFlag){ + fout.printtab(" ", this.field); + fout.printtab(" ", this.field); + fout.printtab(" ", this.field); + fout.println("variation (%)"); + } + else{ + fout.println(" "); + } + + if(this.lastMethod==38){ + int nT = 3; + int ii = 0; + for(int i=0; i<nT; i++){ + fout.printtab(this.paraName[i], this.field); + if(this.fixed[i]){ + fout.printtab(this.values[i]); + fout.println(" fixed parameter"); + } + else{ + if(invertFlag){ + fout.printtab(Fmath.truncate(best[ii],this.prec), this.field); + fout.printtab(Fmath.truncate(bestSd[ii],this.prec), this.field); + fout.printtab(Fmath.truncate(Math.abs(bestSd[ii]*100.0D/best[ii]),this.prec), this.field); + fout.printtab(Fmath.truncate(tValues[ii],this.prec), this.field); + fout.println(Fmath.truncate(pValues[ii],this.prec)); + } + else{ + fout.println(Fmath.truncate(best[ii],this.prec)); + } + ii++; + } + } + } + else{ + for(int i=0; i<this.nTerms; i++){ + if(invertFlag){ + fout.printtab(this.paraName[i], this.field); + fout.printtab(Fmath.truncate(best[i],this.prec), this.field); + fout.printtab(Fmath.truncate(bestSd[i],this.prec), this.field); + fout.printtab(Fmath.truncate(Math.abs(bestSd[i]*100.0D/best[i]),this.prec), this.field); + fout.printtab(Fmath.truncate(tValues[i],this.prec), this.field); + fout.println(Fmath.truncate(pValues[i],this.prec)); + } + else{ + fout.printtab(this.paraName[i], this.field); + fout.println(Fmath.truncate(best[i],this.prec)); + } + } + } + fout.println(); + + fout.printtab(" ", this.field); + fout.printtab("Best", this.field); + fout.printtab("Pre-min", this.field); + fout.printtab("Post-min", this.field); + fout.printtab("Initial", this.field); + fout.printtab("Fractional", this.field); + fout.println("Scaling"); + + fout.printtab(" ", this.field); + fout.printtab("estimate", this.field); + fout.printtab("gradient", this.field); + fout.printtab("gradient", this.field); + fout.printtab("estimate", this.field); + fout.printtab("step", this.field); + fout.println("factor"); + + + if(this.lastMethod==38){ + int nT = 3; + int ii = 0; + for(int i=0; i<nT; i++){ + fout.printtab(this.paraName[i], this.field); + if(this.fixed[i]){ + fout.printtab(this.values[i]); + fout.println(" fixed parameter"); + } + else{ + fout.printtab(Fmath.truncate(best[ii],this.prec), this.field); + fout.printtab(Fmath.truncate(this.grad[ii][0],this.prec), this.field); + fout.printtab(Fmath.truncate(this.grad[ii][1],this.prec), this.field); + fout.printtab(Fmath.truncate(this.startH[ii],this.prec), this.field); + fout.printtab(Fmath.truncate(this.stepH[ii],this.prec), this.field); + fout.println(Fmath.truncate(this.scale[ii],this.prec)); + ii++; + } + } + } + else{ + for(int i=0; i<this.nTerms; i++){ + fout.printtab(this.paraName[i], this.field); + fout.printtab(Fmath.truncate(best[i],this.prec), this.field); + fout.printtab(Fmath.truncate(this.grad[i][0],this.prec), this.field); + fout.printtab(Fmath.truncate(this.grad[i][1],this.prec), this.field); + fout.printtab(Fmath.truncate(this.startH[i],this.prec), this.field); + fout.printtab(Fmath.truncate(this.stepH[i],this.prec), this.field); + fout.println(Fmath.truncate(this.scale[i],this.prec)); + } + } + fout.println(); + + + + ErrorProp ePeak = null; + ErrorProp eYscale = null; + if(this.scaleFlag){ + switch(this.lastMethod){ + case 4: ErrorProp eSigma = new ErrorProp(best[1], bestSd[1]); + eYscale = new ErrorProp(best[2]/Math.sqrt(2.0D*Math.PI), bestSd[2]/Math.sqrt(2.0D*Math.PI)); + ePeak = eYscale.over(eSigma); + fout.printsp("Calculated estimate of the peak value = "); + fout.println(ErrorProp.truncate(ePeak, prec)); + break; + case 5: ErrorProp eGamma = new ErrorProp(best[1], bestSd[1]); + eYscale = new ErrorProp(2.0D*best[2]/Math.PI, 2.0D*bestSd[2]/Math.PI); + ePeak = eYscale.over(eGamma); + fout.printsp("Calculated estimate of the peak value = "); + fout.println(ErrorProp.truncate(ePeak, prec)); + break; + + } + } + if(this.lastMethod==25){ + fout.printsp("Calculated estimate of the maximum gradient = "); + if(this.scaleFlag){ + fout.println(Fmath.truncate(best[0]*best[2]/4.0D, prec)); + } + else{ + fout.println(Fmath.truncate(best[0]*this.yScaleFactor/4.0D, prec)); + } + + } + if(this.lastMethod==28){ + fout.printsp("Calculated estimate of the maximum gradient = "); + if(this.scaleFlag){ + fout.println(Fmath.truncate(best[1]*best[2]/(4.0D*best[0]), prec)); + } + else{ + fout.println(Fmath.truncate(best[1]*this.yScaleFactor/(4.0D*best[0]), prec)); + } + fout.printsp("Calculated estimate of the Ka, i.e. theta raised to the power n = "); + fout.println(Fmath.truncate(Math.pow(best[0], best[1]), prec)); + } + fout.println(); + + int kk=0; + for(int j=0; j<nYarrays; j++){ + if(this.multipleY)fout.println("Y array " + j); + + for(int i=0; i<this.nXarrays; i++){ + fout.printtab("x"+String.valueOf(i), this.field); + } + + fout.printtab("y(expl)", this.field); + fout.printtab("y(calc)", this.field); + fout.printtab("weight", this.field); + fout.printtab("residual", this.field); + fout.println("residual"); + + for(int i=0; i<this.nXarrays; i++){ + fout.printtab(" ", this.field); + } + fout.printtab(" ", this.field); + fout.printtab(" ", this.field); + fout.printtab(" ", this.field); + fout.printtab("(unweighted)", this.field); + fout.println("(weighted)"); + for(int i=0; i<this.nData0; i++){ + for(int jj=0; jj<this.nXarrays; jj++){ + fout.printtab(Fmath.truncate(this.xData[jj][kk],this.prec), this.field); + } + fout.printtab(Fmath.truncate(this.yData[kk],this.prec), this.field); + fout.printtab(Fmath.truncate(this.yCalc[kk],this.prec), this.field); + fout.printtab(Fmath.truncate(this.weight[kk],this.prec), this.field); + fout.printtab(Fmath.truncate(this.residual[kk],this.prec), this.field); + fout.println(Fmath.truncate(this.residualW[kk],this.prec)); + kk++; + } + fout.println(); + } + + fout.printtab("Sum of squares of the unweighted residuals"); + fout.println(Fmath.truncate(this.sumOfSquares,this.prec)); + if(this.trueFreq){ + fout.printtab("Chi Square (Poissonian bins)"); + fout.println(Fmath.truncate(this.chiSquare,this.prec)); + fout.printtab("Reduced Chi Square (Poissonian bins)"); + fout.println(Fmath.truncate(this.reducedChiSquare,this.prec)); + fout.printtab("Chi Square (Poissonian bins) Probability"); + fout.println(Fmath.truncate(1.0D-Stat.chiSquareProb(this.reducedChiSquare,this.degreesOfFreedom),this.prec)); + } + else{ + if(weightOpt){ + fout.printtab("Chi Square"); + fout.println(Fmath.truncate(this.chiSquare,this.prec)); + fout.printtab("Reduced Chi Square"); + fout.println(Fmath.truncate(this.reducedChiSquare,this.prec)); + fout.printtab("Chi Square Probability"); + fout.println(Fmath.truncate(this.getchiSquareProb(),this.prec)); + } + } + + fout.println(" "); + fout.println("Correlation: x - y data"); + if(this.nXarrays>1){ + fout.printtab(this.weightWord[this.weightFlag] + "Multiple Sample Correlation Coefficient (R)"); + fout.println(Fmath.truncate(this.sampleR, this.prec)); + fout.printtab(this.weightWord[this.weightFlag] + "Multiple Sample Correlation Coefficient Squared (R^2)"); + fout.println(Fmath.truncate(this.sampleR2, this.prec)); + if(this.sampleR2<=1.0D){ + fout.printtab(this.weightWord[this.weightFlag] + "Multiple Sample Correlation Coefficient F-test ratio"); + fout.println(Fmath.truncate(this.multipleF, this.prec)); + fout.printtab(this.weightWord[this.weightFlag] + "Multiple Sample Correlation Coefficient F-test probability"); + fout.println(Stat.fTestProb(this.multipleF, this.nXarrays-1, this.nData-this.nXarrays)); + } + fout.printtab(this.weightWord[this.weightFlag] + "Adjusted Multiple Sample Correlation Coefficient (adjR)"); + fout.println(Fmath.truncate(this.adjustedR, this.prec)); + fout.printtab(this.weightWord[this.weightFlag] + "Adjusted Multiple Sample Correlation Coefficient Squared (adjR*adjR)"); + fout.println(Fmath.truncate(this.adjustedR2, this.prec)); + if(this.sampleR2<=1.0D){ + fout.printtab(this.weightWord[this.weightFlag] + "Multiple Sample Correlation Coefficient F-test ratio"); + fout.println(Fmath.truncate(this.adjustedF, this.prec)); + fout.printtab(this.weightWord[this.weightFlag] + "Multiple Sample Correlation Coefficient F-test probability"); + fout.println(Stat.fTestProb(this.adjustedF, this.nXarrays-1, this.nData-this.nXarrays)); + } + } + else{ + fout.printtab(this.weightWord[this.weightFlag] + "Sample Correlation Coefficient (R)"); + fout.println(Fmath.truncate(this.sampleR, this.prec)); + fout.printtab(this.weightWord[this.weightFlag] + "Sample Correlation Coefficient Squared (R^2)"); + fout.println(Fmath.truncate(this.sampleR2, this.prec)); + + } + + fout.println(" "); + fout.println("Correlation: y(experimental) - y(calculated)"); + fout.printtab(this.weightWord[this.weightFlag] + "Linear Correlation Coefficient"); + double ccyy = Stat.corrCoeff(this.yData, this.yCalc, this.weight); + fout.println(Fmath.truncate(ccyy, this.prec)); + fout.printtab(this.weightWord[this.weightFlag] + "Linear Correlation Coefficient Probability"); + fout.println(Fmath.truncate(Stat.linearCorrCoeffProb(ccyy, this.nData-1),this.prec)); + + fout.println(" "); + fout.printtab("Degrees of freedom"); + fout.println(this.degreesOfFreedom); + fout.printtab("Number of data points"); + fout.println(this.nData); + fout.printtab("Number of estimated paramaters"); + fout.println(this.nTerms); + + fout.println(); + + if(this.posVarFlag && this.invertFlag && this.chiSquare!=0.0D){ + fout.println("Parameter - parameter correlation coefficients"); + fout.printtab(" ", this.field); + for(int i=0; i<this.nTerms;i++){ + fout.printtab(paraName[i], this.field); + } + fout.println(); + + for(int j=0; j<this.nTerms;j++){ + fout.printtab(paraName[j], this.field); + for(int i=0; i<this.nTerms;i++){ + fout.printtab(Fmath.truncate(this.corrCoeff[i][j], this.prec), this.field); + } + fout.println(); + } + fout.println(); + } + + fout.println(); + fout.printtab("Number of iterations taken"); + fout.println(this.nIter); + fout.printtab("Maximum number of iterations allowed"); + fout.println(this.nMax); + fout.printtab("Number of restarts taken"); + fout.println(this.kRestart); + fout.printtab("Maximum number of restarts allowed"); + fout.println(this.konvge); + fout.printtab("Standard deviation of the simplex at the minimum"); + fout.println(Fmath.truncate(this.simplexSd, this.prec)); + fout.printtab("Convergence tolerance"); + fout.println(this.fTol); + switch(minTest){ + case 0: fout.println("simplex sd < the tolerance times the mean of the absolute values of the y values"); + break; + case 1: fout.println("simplex sd < the tolerance"); + break; + case 2: fout.println("simplex sd < the tolerance times the square root(sum of squares/degrees of freedom"); + break; + } + fout.println("Step used in numerical differentiation to obtain Hessian matrix"); + fout.println("d(parameter) = parameter*"+this.delta); + + fout.println(); + fout.println("End of file"); + fout.close(); + } + + // plot calculated y against experimental y + // title provided + public void plotYY(String title){ + this.graphTitle = title; + int ncurves = 2; + int npoints = this.nData0; + double[][] data = PlotGraph.data(ncurves, npoints); + + int kk = 0; + for(int jj=0; jj<this.nYarrays; jj++){ + + // fill first curve with experimental versus best fit values + for(int i=0; i<nData0; i++){ + data[0][i]=this.yData[kk]; + data[1][i]=this.yCalc[kk]; + kk++; + } + + // Create a title + String title0 = this.setGandPtitle(this.graphTitle); + if(this.multipleY)title0 = title0 + "y array " + jj; + String title1 = "Calculated versus experimental y values"; + + // Calculate best fit straight line between experimental and best fit values + Regression yyRegr = new Regression(this.yData, this.yCalc, this.weight); + yyRegr.linear(); + double[] coef = yyRegr.getCoeff(); + data[2][0]=Fmath.minimum(this.yData); + data[3][0]=coef[0]+coef[1]*data[2][0]; + data[2][1]=Fmath.maximum(this.yData); + data[3][1]=coef[0]+coef[1]*data[2][1]; + + PlotGraph pg = new PlotGraph(data); + + pg.setGraphTitle(title0); + pg.setGraphTitle2(title1); + pg.setXaxisLegend("Experimental y value"); + pg.setYaxisLegend("Calculated y value"); + int[] popt = {1, 0}; + pg.setPoint(popt); + int[] lopt = {0, 3}; + pg.setLine(lopt); + + pg.plot(); + } + } + + //Creates a title + protected String setGandPtitle(String title){ + String title1 = ""; + switch(this.lastMethod){ + case 0: title1 = "Linear regression (with intercept): "+title; + break; + case 1: title1 = "Linear(polynomial with degree = " + (nTerms-1) + ") regression: "+title; + break; + case 2: title1 = "General linear regression: "+title; + break; + case 3: title1 = "Non-linear (simplex) regression: "+title; + break; + case 4: title1 = "Fit to a Gaussian distribution: "+title; + break; + case 5: title1 = "Fit to a Lorentzian distribution: "+title; + break; + case 6:title1 = "Fit to a Poisson distribution: "+title; + break; + case 7: title1 = "Fit to a Two Parameter Minimum Order Statistic Gumbel distribution: "+title; + break; + case 8: title1 = "Fit to a two Parameter Maximum Order Statistic Gumbel distribution: "+title; + break; + case 9: title1 = "Fit to a One Parameter Minimum Order Statistic Gumbel distribution: "+title; + break; + case 10: title1 = "Fit to a One Parameter Maximum Order Statistic Gumbel distribution: "+title; + break; + case 11: title1 = "Fit to a Standard Minimum Order Statistic Gumbel distribution: "+title; + break; + case 12: title1 = "Fit to a Standard Maximum Order Statistic Gumbel distribution: "+title; + break; + case 13:title1 = "Fit to a Three Parameter Frechet distribution: "+title; + break; + case 14:title1 = "Fit to a Two Parameter Frechet distribution: "+title; + break; + case 15:title1 = "Fit to a Standard Frechet distribution: "+title; + break; + case 16:title1 = "Fit to a Three Parameter Weibull distribution: "+title; + break; + case 17:title1 = "Fit to a Two Parameter Weibull distribution: "+title; + break; + case 18:title1 = "Fit to a Standard Weibull distribution: "+title; + break; + case 19:title1 = "Fit to a Two Parameter Exponential distribution: "+title; + break; + case 20:title1 = "Fit to a One Parameter Exponential distribution: "+title; + break; + case 21:title1 = "Fit to a Standard exponential distribution: "+title; + break; + case 22:title1 = "Fit to a Rayleigh distribution: "+title; + break; + case 23:title1 = "Fit to a Two Parameter Pareto distribution: "+title; + break; + case 24:title1 = "Fit to a One Parameter Pareto distribution: "+title; + break; + case 25:title1 = "Fit to a Sigmoid Threshold Function: "+title; + break; + case 26:title1 = "Fit to a Rectangular Hyperbola: "+title; + break; + case 27:title1 = "Fit to a Scaled Heaviside Step Function: "+title; + break; + case 28:title1 = "Fit to a Hill/Sips Sigmoid: "+title; + break; + case 29:title1 = "Fit to a Shifted Pareto distribution: "+title; + break; + case 30:title1 = "Fit to a Logistic distribution: "+title; + break; + case 31:title1 = "Fit to a Beta distribution - interval [0, 1]: "+title; + break; + case 32:title1 = "Fit to a Beta distribution - interval [min, max]: "+title; + break; + case 33:title1 = "Fit to a Three Parameter Gamma distribution]: "+title; + break; + case 34:title1 = "Fit to a Standard Gamma distribution]: "+title; + break; + case 35:title1 = "Fit to an Erlang distribution]: "+title; + break; + case 36:title1 = "Fit to an two parameter log-normal distribution]: "+title; + break; + case 37:title1 = "Fit to an three parameter log-normal distribution]: "+title; + break; + case 38: title1 = "Fit to a Gaussian distribution with fixed parameters: "+title; + break; + case 39: title1 = "Fit to a EC50 dose response curve: "+title; + break; + case 40: title1 = "Fit to a LogEC50 dose response curve: "+title; + break; + case 41: title1 = "Fit to a EC50 dose response curve - bottom constrained [>= 0]: "+title; + break; + case 42: title1 = "Fit to a LogEC50 dose response curve - bottom constrained [>= 0]: "+title; + break; + case 43: title1 = "Fit to an exponential yscale.exp(A.x): "+title; + break; + case 44: title1 = "Fit to multiple exponentials sum[Ai.exp(Bi.x)]: "+title; + break; + + default: title1 = " "+title; + } + return title1; + } + + // plot calculated y against experimental y + // no title provided + public void plotYY(){ + plotYY(this.graphTitle); + } + + // plot experimental x against experimental y and against calculated y + // linear regression data + // title provided + protected int plotXY(String title){ + this.graphTitle = title; + int flag=0; + if(!this.linNonLin && this.nTerms>0){ + System.out.println("You attempted to use Regression.plotXY() for a non-linear regression without providing the function reference (pointer) in the plotXY argument list"); + System.out.println("No plot attempted"); + flag=-1; + return flag; + } + flag = this.plotXYlinear(title); + return flag; + } + + // plot experimental x against experimental y and against calculated y + // Linear regression data + // no title provided + public int plotXY(){ + int flag = plotXY(this.graphTitle); + return flag; + } + + // plot experimental x against experimental y and against calculated y + // non-linear regression data + // title provided + // matching simplex + protected int plotXY(RegressionFunction g, String title){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y array\nplotXY2 should have been called"); + Object regFun = (Object)g; + int flag = this.plotXYnonlinear(regFun, title); + return flag; + } + + // plot experimental x against experimental y and against calculated y + // non-linear regression data + // title provided + // matching simplex2 + protected int plotXY2(RegressionFunction2 g, String title){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nsimplex should have been called"); + this.graphTitle = title; + Object regFun = (Object)g; + int flag = this.plotXYnonlinear(regFun, title); + return flag; + } + + // plot experimental x against experimental y and against calculated y + // non-linear regression data + // no title provided + // matches simplex + protected int plotXY(RegressionFunction g){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y array\nplotXY2 should have been called"); + Object regFun = (Object)g; + int flag = this.plotXYnonlinear(regFun, this.graphTitle); + return flag; + } + + // plot experimental x against experimental y and against calculated y + // non-linear regression data + // no title provided + // matches simplex2 + protected int plotXY2(RegressionFunction2 g){ + if(!this.multipleY)throw new IllegalArgumentException("This method cannot handle singly dimensioned y array\nplotXY should have been called"); + Object regFun = (Object)g; + int flag = this.plotXYnonlinear(regFun, this.graphTitle); + return flag; + } + + // Add legends option + public void addLegends(){ + int ans = JOptionPane.showConfirmDialog(null, "Do you wish to add your own legends to the x and y axes", "Axis Legends", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if(ans==0){ + this.xLegend = JOptionPane.showInputDialog("Type the legend for the abscissae (x-axis) [first data set]" ); + this.yLegend = JOptionPane.showInputDialog("Type the legend for the ordinates (y-axis) [second data set]" ); + this.legendCheck = true; + } + } + + // protected method for plotting experimental x against experimental y and against calculated y + // Linear regression + // title provided + protected int plotXYlinear(String title){ + this.graphTitle = title; + int flag=0; //Returned as 0 if plot data can be plotted, -1 if not, -2 if tried multiple regression plot + if(this.nXarrays>1){ + System.out.println("You attempted to use Regression.plotXY() for a multiple regression"); + System.out.println("No plot attempted"); + flag=-2; + return flag; + } + + int ncurves = 2; + int npoints = 200; + if(npoints<this.nData0)npoints=this.nData0; + if(this.lastMethod==11 || this.lastMethod==12 || this.lastMethod==21)npoints=this.nData0; + double[][] data = PlotGraph.data(ncurves, npoints); + double xmin =Fmath.minimum(xData[0]); + double xmax =Fmath.maximum(xData[0]); + double inc = (xmax - xmin)/(double)(npoints - 1); + String title1 = " "; + String title2 = " "; + + for(int i=0; i<nData0; i++){ + data[0][i] = this.xData[0][i]; + data[1][i] = this.yData[i]; + } + + data[2][0]=xmin; + for(int i=1; i<npoints; i++)data[2][i] = data[2][i-1] + inc; + if(this.nTerms==0){ + switch(this.lastMethod){ + case 11: title1 = "No regression: Minimum Order Statistic Standard Gumbel (y = exp(x)exp(-exp(x))): "+this.graphTitle; + title2 = " points - experimental values; line - theoretical curve; no parameters to be estimated"; + if(weightOpt)title2 = title2 +"; error bars - weighting factors"; + for(int i=0; i<npoints; i++)data[3][i] = this.yCalc[i]; + break; + case 12: title1 = "No regression: Maximum Order Statistic Standard Gumbel (y = exp(-x)exp(-exp(-x))): "+this.graphTitle; + title2 = " points - experimental values; line - theoretical curve; no parameters to be estimated"; + if(weightOpt)title2 = title2 +"; error bars - weighting factors"; + for(int i=0; i<npoints; i++)data[3][i] = this.yCalc[i]; + break; + case 21: title1 = "No regression: Standard Exponential (y = exp(-x)): "+this.graphTitle; + title2 = " points - experimental values; line - theoretical curve; no parameters to be estimated"; + if(weightOpt)title2 = title2 +"; error bars - weighting factors"; + for(int i=0; i<npoints; i++)data[3][i] = this.yCalc[i]; + break; + } + + } + else{ + switch(this.lastMethod){ + case 0: title1 = "Linear regression (y = a + b.x): "+this.graphTitle; + title2 = " points - experimental values; line - best fit curve"; + if(weightOpt)title2 = title2 +"; error bars - weighting factors"; + for(int i=0; i<npoints; i++)data[3][i] = best[0] + best[1]*data[2][i]; + break; + case 1: title1 = "Linear (polynomial with degree = " + (nTerms-1) + ") regression: "+this.graphTitle; + title2 = " points - experimental values; line - best fit curve"; + if(weightOpt)title2 = title2 +"; error bars - weighting factors"; + for(int i=0; i<npoints; i++){ + double sum=best[0]; + for(int j=1; j<this.nTerms; j++)sum+=best[j]*Math.pow(data[2][i],j); + data[3][i] = sum; + } + break; + case 2: title1 = "Linear regression (y = a.x): "+this.graphTitle; + title2 = " points - experimental values; line - best fit curve"; + if(this.nXarrays==1){ + if(weightOpt)title2 = title2 +"; error bars - weighting factors"; + for(int i=0; i<npoints; i++)data[3][i] = best[0]*data[2][i]; + } + else{ + System.out.println("Regression.plotXY(linear): lastMethod, "+lastMethod+",cannot be plotted in two dimensions"); + System.out.println("No plot attempted"); + flag=-1; + } + break; + case 11: title1 = "Linear regression: Minimum Order Statistic Standard Gumbel (y = a.z where z = exp(x)exp(-exp(x))): "+this.graphTitle; + title2 = " points - experimental values; line - best fit curve"; + if(weightOpt)title2 = title2 +"; error bars - weighting factors"; + for(int i=0; i<npoints; i++)data[3][i] = best[0]*Math.exp(data[2][i])*Math.exp(-Math.exp(data[2][i])); + break; + case 12: title1 = "Linear regression: Maximum Order Statistic Standard Gumbel (y = a.z where z=exp(-x)exp(-exp(-x))): "+this.graphTitle; + title2 = " points - experimental values; line - best fit curve"; + if(weightOpt)title2 = title2 +"; error bars - weighting factors"; + for(int i=0; i<npoints; i++)data[3][i] = best[0]*Math.exp(-data[2][i])*Math.exp(-Math.exp(-data[2][i])); + break; + default: System.out.println("Regression.plotXY(linear): lastMethod, "+lastMethod+", either not recognised or cannot be plotted in two dimensions"); + System.out.println("No plot attempted"); + flag=-1; + return flag; + } + } + + PlotGraph pg = new PlotGraph(data); + + pg.setGraphTitle(title1); + pg.setGraphTitle2(title2); + pg.setXaxisLegend(this.xLegend); + pg.setYaxisLegend(this.yLegend); + int[] popt = {1,0}; + pg.setPoint(popt); + int[] lopt = {0,3}; + pg.setLine(lopt); + if(weightOpt)pg.setErrorBars(0,this.weight); + pg.plot(); + + return flag; + } + + // protected method for plotting experimental x against experimental y and against calculated y + // Non-linear regression + // title provided + public int plotXYnonlinear(Object regFun, String title){ + this.graphTitle = title; + RegressionFunction g1 = null; + RegressionFunction2 g2 = null; + if(this.multipleY){ + g2 = (RegressionFunction2)regFun; + } + else{ + g1 = (RegressionFunction)regFun; + } + + int flag=0; //Returned as 0 if plot data can be plotted, -1 if not + + if(this.lastMethod<3){ + System.out.println("Regression.plotXY(non-linear): lastMethod, "+lastMethod+", either not recognised or cannot be plotted in two dimensions"); + System.out.println("No plot attempted"); + flag=-1; + return flag; + } + + if(this.nXarrays>1){ + System.out.println("Multiple Linear Regression with more than one independent variable cannot be plotted in two dimensions"); + System.out.println("plotYY() called instead of plotXY()"); + this.plotYY(title); + flag=-2; + } + else{ + if(this.multipleY){ + int ncurves = 2; + int npoints = 200; + if(npoints<this.nData0)npoints=this.nData0; + String title1, title2; + int kk=0; + double[] wWeight = new double[this.nData0]; + for(int jj=0; jj<this.nYarrays; jj++){ + double[][] data = PlotGraph.data(ncurves, npoints); + for(int i=0; i<this.nData0; i++){ + data[0][i] = this.xData[0][kk]; + data[1][i] = this.yData[kk]; + wWeight[i] = this.weight[kk]; + kk++; + } + double xmin =Fmath.minimum(xData[0]); + double xmax =Fmath.maximum(xData[0]); + double inc = (xmax - xmin)/(double)(npoints - 1); + data[2][0]=xmin; + for(int i=1; i<npoints; i++)data[2][i] = data[2][i-1] + inc; + double[] xd = new double[this.nXarrays]; + for(int i=0; i<npoints; i++){ + xd[0] = data[2][i]; + data[3][i] = g2.function(best, xd, jj*this.nData0); + } + + // Create a title + title1 = this.setGandPtitle(title); + title2 = " points - experimental values; line - best fit curve; y data array " + jj; + if(weightOpt)title2 = title2 +"; error bars - weighting factors"; + + PlotGraph pg = new PlotGraph(data); + + pg.setGraphTitle(title1); + pg.setGraphTitle2(title2); + pg.setXaxisLegend(this.xLegend); + pg.setYaxisLegend(this.yLegend); + int[] popt = {1,0}; + pg.setPoint(popt); + int[] lopt = {0,3}; + pg.setLine(lopt); + if(weightOpt)pg.setErrorBars(0,wWeight); + + pg.plot(); + } + } + else{ + int ncurves = 2; + int npoints = 200; + if(npoints<this.nData0)npoints=this.nData0; + if(this.lastMethod==6)npoints=this.nData0; + String title1, title2; + double[][] data = PlotGraph.data(ncurves, npoints); + for(int i=0; i<this.nData0; i++){ + data[0][i] = this.xData[0][i]; + data[1][i] = this.yData[i]; + } + if(this.lastMethod==6){ + double[] xd = new double[this.nXarrays]; + for(int i=0; i<npoints; i++){ + data[2][i]=data[0][i]; + xd[0] = data[2][i]; + data[3][i] = g1.function(best, xd); + } + } + else{ + double xmin =Fmath.minimum(xData[0]); + double xmax =Fmath.maximum(xData[0]); + double inc = (xmax - xmin)/(double)(npoints - 1); + data[2][0]=xmin; + for(int i=1; i<npoints; i++)data[2][i] = data[2][i-1] + inc; + double[] xd = new double[this.nXarrays]; + for(int i=0; i<npoints; i++){ + xd[0] = data[2][i]; + data[3][i] = g1.function(best, xd); + } + } + + // Create a title + title1 = this.setGandPtitle(title); + title2 = " points - experimental values; line - best fit curve"; + if(weightOpt)title2 = title2 +"; error bars - weighting factors"; + + PlotGraph pg = new PlotGraph(data); + + pg.setGraphTitle(title1); + pg.setGraphTitle2(title2); + pg.setXaxisLegend(this.xLegend); + pg.setYaxisLegend(this.yLegend); + int[] popt = {1,0}; + pg.setPoint(popt); + int[] lopt = {0,3}; + pg.setLine(lopt); + + if(weightOpt)pg.setErrorBars(0,this.weight); + + pg.plot(); + } + } + return flag; + } + + // protected method for plotting experimental x against experimental y and against calculated y + // Non-linear regression + // all parameters fixed + public int plotXYfixed(Object regFun, String title){ + this.graphTitle = title; + RegressionFunction g1 = null; + RegressionFunction2 g2 = null; + if(this.multipleY){ + g2 = (RegressionFunction2)regFun; + } + else{ + g1 = (RegressionFunction)regFun; + } + + int flag=0; //Returned as 0 if plot data can be plotted, -1 if not + + if(this.lastMethod<3){ + System.out.println("Regression.plotXY(non-linear): lastMethod, "+lastMethod+", either not recognised or cannot be plotted in two dimensions"); + System.out.println("No plot attempted"); + flag=-1; + return flag; + } + + + if(this.nXarrays>1){ + System.out.println("Multiple Linear Regression with more than one independent variable cannot be plotted in two dimensions"); + System.out.println("plotYY() called instead of plotXY()"); + this.plotYY(title); + flag=-2; + } + else{ + if(this.multipleY){ + int ncurves = 2; + int npoints = 200; + if(npoints<this.nData0)npoints=this.nData0; + String title1, title2; + int kk=0; + double[] wWeight = new double[this.nData0]; + for(int jj=0; jj<this.nYarrays; jj++){ + double[][] data = PlotGraph.data(ncurves, npoints); + for(int i=0; i<this.nData0; i++){ + data[0][i] = this.xData[0][kk]; + data[1][i] = this.yData[kk]; + wWeight[i] = this.weight[kk]; + kk++; + } + double xmin =Fmath.minimum(xData[0]); + double xmax =Fmath.maximum(xData[0]); + double inc = (xmax - xmin)/(double)(npoints - 1); + data[2][0]=xmin; + for(int i=1; i<npoints; i++)data[2][i] = data[2][i-1] + inc; + double[] xd = new double[this.nXarrays]; + for(int i=0; i<npoints; i++){ + xd[0] = data[2][i]; + data[3][i] = g2.function(this.values, xd, jj*this.nData0); + } + + // Create a title + title1 = this.setGandPtitle(title); + title2 = " points - experimental values; line - best fit curve; y data array " + jj; + if(weightOpt)title2 = title2 +"; error bars - weighting factors"; + + PlotGraph pg = new PlotGraph(data); + + pg.setGraphTitle(title1); + pg.setGraphTitle2(title2); + pg.setXaxisLegend(this.xLegend); + pg.setYaxisLegend(this.yLegend); + int[] popt = {1,0}; + pg.setPoint(popt); + int[] lopt = {0,3}; + pg.setLine(lopt); + if(weightOpt)pg.setErrorBars(0,wWeight); + + pg.plot(); + } + } + else{ + int ncurves = 2; + int npoints = 200; + if(npoints<this.nData0)npoints=this.nData0; + if(this.lastMethod==6)npoints=this.nData0; + String title1, title2; + double[][] data = PlotGraph.data(ncurves, npoints); + for(int i=0; i<this.nData0; i++){ + data[0][i] = this.xData[0][i]; + data[1][i] = this.yData[i]; + } + if(this.lastMethod==6){ + double[] xd = new double[this.nXarrays]; + for(int i=0; i<npoints; i++){ + data[2][i]=data[0][i]; + xd[0] = data[2][i]; + data[3][i] = g1.function(this.values, xd); + } + } + else{ + double xmin =Fmath.minimum(xData[0]); + double xmax =Fmath.maximum(xData[0]); + double inc = (xmax - xmin)/(double)(npoints - 1); + data[2][0]=xmin; + for(int i=1; i<npoints; i++)data[2][i] = data[2][i-1] + inc; + double[] xd = new double[this.nXarrays]; + for(int i=0; i<npoints; i++){ + xd[0] = data[2][i]; + data[3][i] = g1.function(this.values, xd); + } + } + + // Create a title + title1 = this.setGandPtitle(title); + title2 = " points - experimental values; line - best fit curve"; + if(weightOpt)title2 = title2 +"; error bars - weighting factors"; + + PlotGraph pg = new PlotGraph(data); + + pg.setGraphTitle(title1); + pg.setGraphTitle2(title2); + pg.setXaxisLegend(this.xLegend); + pg.setYaxisLegend(this.yLegend); + int[] popt = {1,0}; + pg.setPoint(popt); + int[] lopt = {0,3}; + pg.setLine(lopt); + + if(weightOpt)pg.setErrorBars(0,this.weight); + + pg.plot(); + } + } + return flag; + } + + + // Get the non-linear regression status + // true if convergence was achieved + // false if convergence not achieved before maximum number of iterations + // current values then returned + public boolean getNlrStatus(){ + return this.nlrStatus; + } + + // Reset scaling factors (scaleOpt 0 and 1, see below for scaleOpt 2) + public void setScale(int n){ + if(n<0 || n>1)throw new IllegalArgumentException("The argument must be 0 (no scaling) 1(initial estimates all scaled to unity) or the array of scaling factors"); + this.scaleOpt=n; + } + + // Reset scaling factors (scaleOpt 2, see above for scaleOpt 0 and 1) + public void setScale(double[] sc){ + this.scale=sc; + this.scaleOpt=2; + } + + // Get scaling factors + public double[] getScale(){ + return this.scale; + } + + // Reset the non-linear regression convergence test option + public void setMinTest(int n){ + if(n<0 || n>1)throw new IllegalArgumentException("minTest must be 0 or 1"); + this.minTest=n; + } + + // Get the non-linear regression convergence test option + public int getMinTest(){ + return this.minTest; + } + + // Get the simplex sd at the minimum + public double getSimplexSd(){ + return this.simplexSd; + } + + // Get the best estimates of the unknown parameters + public double[] getBestEstimates(){ + return best.clone(); + } + + // Get the best estimates of the unknown parameters + public double[] getCoeff(){ + return best.clone(); + } + + // Get the estimates of the standard deviations of the best estimates of the unknown parameters + public double[] getbestestimatesStandardDeviations(){ + return bestSd.clone(); + } + + // Get the estimates of the errors of the best estimates of the unknown parameters + public double[] getBestEstimatesStandardDeviations(){ + return bestSd.clone(); + } + + // Get the estimates of the errors of the best estimates of the unknown parameters + public double[] getCoeffSd(){ + return bestSd.clone(); + } + + // Get the estimates of the errors of the best estimates of the unknown parameters + public double[] getBestEstimatesErrors(){ + return bestSd.clone(); + } + + // Get the unscaled initial estimates of the unknown parameters + public double[] getInitialEstimates(){ + return startH.clone(); + } + + // Get the scaled initial estimates of the unknown parameters + public double[] getScaledInitialEstimates(){ + return startSH.clone(); + } + + // Get the unscaled initial step sizes + public double[] getInitialSteps(){ + return stepH.clone(); + } + + // Get the scaled initial step sizesp + public double[] getScaledInitialSteps(){ + return stepSH.clone(); + } + + // Get the cofficients of variations of the best estimates of the unknown parameters + public double[] getCoeffVar(){ + double[] coeffVar = new double[this.nTerms]; + + for(int i=0; i<this.nTerms; i++){ + coeffVar[i]=bestSd[i]*100.0D/best[i]; + } + return coeffVar; + } + + // Get the pseudo-estimates of the errors of the best estimates of the unknown parameters + public double[] getPseudoSd(){ + return pseudoSd.clone(); + } + + // Get the pseudo-estimates of the errors of the best estimates of the unknown parameters + public double[] getPseudoErrors(){ + return pseudoSd.clone(); + } + + // Get the t-values of the best estimates + public double[] getTvalues(){ + return tValues.clone(); + } + + // Get the p-values of the best estimates + public double[] getPvalues(){ + return pValues.clone(); + } + + + // Get the inputted x values + public double[][] getXdata(){ + return xData.clone(); + } + + // Get the inputted y values + public double[] getYdata(){ + return yData.clone(); + } + + // Get the calculated y values + public double[] getYcalc(){ + double[] temp = new double[this.nData]; + for(int i=0; i<this.nData; i++)temp[i]=this.yCalc[i]; + return temp; + } + + // Get the unweighted residuals, y(experimental) - y(calculated) + public double[] getResiduals(){ + double[] temp = new double[this.nData]; + for(int i=0; i<this.nData; i++)temp[i]=this.yData[i]-this.yCalc[i]; + return temp; + } + + // Get the weighted residuals, (y(experimental) - y(calculated))/weight + public double[] getWeightedResiduals(){ + + double[] temp = new double[this.nData]; + for(int i=0; i<this.nData; i++)temp[i]=(this.yData[i]-this.yCalc[i])/weight[i]; + return temp; + } + + // Get the unweighted sum of squares of the residuals + public double getSumOfSquares(){ + return this.sumOfSquares; + } + + // Get the chi square estimate + public double getChiSquare(){ + double ret=0.0D; + if(weightOpt){ + ret = this.chiSquare; + } + else{ + System.out.println("Chi Square cannot be calculated as data are neither true frequencies nor weighted"); + System.out.println("A value of -1 is returned as Chi Square"); + ret = -1.0D; + } + return ret; + } + + // Get the reduced chi square estimate + public double getReducedChiSquare(){ + double ret=0.0D; + if(weightOpt){ + ret = this.reducedChiSquare; + } + else{ + System.out.println("A Reduced Chi Square cannot be calculated as data are neither true frequencies nor weighted"); + System.out.println("A value of -1 is returned as Reduced Chi Square"); + ret = -1.0D; + } + return ret; + } + + // Get the chi square probablity + public double getchiSquareProb(){ + double ret=0.0D; + if(weightOpt){ + ret = 1.0D-Stat.chiSquareProb(this.chiSquare, this.nData-this.nXarrays); + } + else{ + System.out.println("A Chi Square probablity cannot be calculated as data are neither true frequencies nor weighted"); + System.out.println("A value of -1 is returned as Reduced Chi Square"); + ret = -1.0D; + } + return ret; + } + + // Get the covariance matrix + public double[][] getCovMatrix(){ + return this.covar; + } + + // Get the correlation coefficient matrix + public double[][] getCorrCoeffMatrix(){ + return this.corrCoeff; + } + + // Get the number of iterations in nonlinear regression + public int getNiter(){ + return this.nIter; + } + + + // Set the maximum number of iterations allowed in nonlinear regression + public void setNmax(int nmax){ + this.nMax = nmax; + } + + // Get the maximum number of iterations allowed in nonlinear regression + public int getNmax(){ + return this.nMax; + } + + // Get the number of restarts in nonlinear regression + public int getNrestarts(){ + return this.kRestart; + } + + // Set the maximum number of restarts allowed in nonlinear regression + public void setNrestartsMax(int nrs){ + this.konvge = nrs; + } + + // Get the maximum number of restarts allowed in nonlinear regression + public int getNrestartsMax(){ + return this.konvge; + } + + // Get the degrees of freedom + public double getDegFree(){ + return (this.degreesOfFreedom); + } + + // Reset the Nelder and Mead reflection coefficient [alpha] + public void setNMreflect(double refl){ + this.rCoeff = refl; + } + + // Get the Nelder and Mead reflection coefficient [alpha] + public double getNMreflect(){ + return this.rCoeff; + } + + // Reset the Nelder and Mead extension coefficient [beta] + public void setNMextend(double ext){ + this.eCoeff = ext; + } + // Get the Nelder and Mead extension coefficient [beta] + public double getNMextend(){ + return this.eCoeff; + } + + // Reset the Nelder and Mead contraction coefficient [gamma] + public void setNMcontract(double con){ + this.cCoeff = con; + } + + // Get the Nelder and Mead contraction coefficient [gamma] + public double getNMcontract(){ + return cCoeff; + } + + // Set the non-linear regression tolerance + public void setTolerance(double tol){ + this.fTol = tol; + } + + + // Get the non-linear regression tolerance + public double getTolerance(){ + return this.fTol; + } + + // Get the non-linear regression pre and post minimum gradients + public double[][] getGrad(){ + return this.grad; + } + + // Set the non-linear regression fractional step size used in numerical differencing + public void setDelta(double delta){ + this.delta = delta; + } + + // Get the non-linear regression fractional step size used in numerical differencing + public double getDelta(){ + return this.delta; + } + + // Get the non-linear regression statistics Hessian matrix inversion status flag + public boolean getInversionCheck(){ + return this.invertFlag; + } + + // Get the non-linear regression statistics Hessian matrix inverse diagonal status flag + public boolean getPosVarCheck(){ + return this.posVarFlag; + } + + + // Test of an additional terms {extra sum of squares] + // return F-ratio, probability, order check and values provided in order used, as Vector + public static Vector<Object> testOfAdditionalTerms(double chiSquareR, int nParametersR, double chiSquareF, int nParametersF, int nPoints){ + ArrayList<Object> res = Regression.testOfAdditionalTerms_ArrayList(chiSquareR, nParametersR, chiSquareF, nParametersF, nPoints); + Vector<Object> ret = null; + if(res!=null){ + int n = ret.size(); + ret = new Vector<Object>(n); + for(int i=0; i<n; i++)ret.addElement(res.get(i)); + } + return ret; + } + + // Test of an additional terms {extra sum of squares] + // return F-ratio, probability, order check and values provided in order used, as Vector + public static Vector<Object> testOfAdditionalTerms_Vector(double chiSquareR, int nParametersR, double chiSquareF, int nParametersF, int nPoints){ + return Regression.testOfAdditionalTerms(chiSquareR, nParametersR, chiSquareF, nParametersF, nPoints); + } + + + // Test of an additional terms {extra sum of squares] + // return F-ratio, probability, order check and values provided in order used, as ArrayList + public static ArrayList<Object> testOfAdditionalTerms_ArrayList(double chiSquareR, int nParametersR, double chiSquareF, int nParametersF, int nPoints){ + int degFreedomR = nPoints - nParametersR; + int degFreedomF = nPoints - nParametersF; + + // Check that model 2 has the lowest degrees of freedom + boolean reversed = false; + if(degFreedomR<degFreedomF){ + reversed = true; + double holdD = chiSquareR; + chiSquareR = chiSquareF; + chiSquareF = holdD; + int holdI = nParametersR; + nParametersR = nParametersF; + nParametersF = holdI; + degFreedomR = nPoints - nParametersR; + degFreedomF = nPoints - nParametersF; + System.out.println("package flanagan.analysis; class Regression; method testAdditionalTerms"); + System.out.println("the order of the chi-squares has been reversed to give a second chi- square with the lowest degrees of freedom"); + } + int degFreedomD = degFreedomR - degFreedomF; + + // F ratio + double numer = (chiSquareR - chiSquareF)/degFreedomD; + double denom = chiSquareF/degFreedomF; + double fRatio = numer/denom; + + // Probability + double fProb = 1.0D; + if(chiSquareR>chiSquareF){ + fProb = Stat.fTestProb(fRatio, degFreedomD, degFreedomF); + } + + // Return arraylist + ArrayList<Object> arrayl = new ArrayList<Object>(); + arrayl.add(new Double(fRatio)); + arrayl.add(new Double(fProb)); + arrayl.add(new Boolean(reversed)); + arrayl.add(new Double(chiSquareR)); + arrayl.add(new Integer(nParametersR)); + arrayl.add(new Double(chiSquareF)); + arrayl.add(new Integer(nParametersF)); + arrayl.add(new Integer(nPoints)); + + return arrayl; + } + + // Test of an additional terms {extra sum of squares] + // return F-ratio only + public double testOfAdditionalTermsFratio(double chiSquareR, int nParametersR, double chiSquareF, int nParametersF, int nPoints){ + int degFreedomR = nPoints - nParametersR; + int degFreedomF = nPoints - nParametersF; + + // Check that model 2 has the lowest degrees of freedom + boolean reversed = false; + if(degFreedomR<degFreedomF){ + reversed = true; + double holdD = chiSquareR; + chiSquareR = chiSquareF; + chiSquareF = holdD; + int holdI = nParametersR; + nParametersR = nParametersF; + nParametersF = holdI; + degFreedomR = nPoints - nParametersR; + degFreedomF = nPoints - nParametersF; + System.out.println("package flanagan.analysis; class Regression; method testAdditionalTermsFratio"); + System.out.println("the order of the chi-squares has been reversed to give a second chi- square with the lowest degrees of freedom"); + } + int degFreedomD = degFreedomR - degFreedomF; + + // F ratio + double numer = (chiSquareR - chiSquareF)/degFreedomD; + double denom = chiSquareF/degFreedomF; + double fRatio = numer/denom; + + return fRatio; + } + + // Test of an additional terms {extra sum of squares] + // return F-distribution probablity only + public double testOfAdditionalTermsFprobabilty(double chiSquareR, int nParametersR, double chiSquareF, int nParametersF, int nPoints){ + int degFreedomR = nPoints - nParametersR; + int degFreedomF = nPoints - nParametersF; + + // Check that model 2 has the lowest degrees of freedom + boolean reversed = false; + if(degFreedomR<degFreedomF){ + reversed = true; + double holdD = chiSquareR; + chiSquareR = chiSquareF; + chiSquareF = holdD; + int holdI = nParametersR; + nParametersR = nParametersF; + nParametersF = holdI; + degFreedomR = nPoints - nParametersR; + degFreedomF = nPoints - nParametersF; + System.out.println("package flanagan.analysis; class Regression; method testAdditionalTermsFprobability"); + System.out.println("the order of the chi-squares has been reversed to give a second chi- square with the lowest degrees of freedom"); + } + int degFreedomD = degFreedomR - degFreedomF; + + // F ratio + double numer = (chiSquareR - chiSquareF)/degFreedomD; + double denom = chiSquareF/degFreedomF; + double fRatio = numer/denom; + + // Probability + double fProb = 1.0D; + if(chiSquareR>chiSquareF){ + fProb = Stat.fTestProb(fRatio, degFreedomD, degFreedomF); + } + + return fProb; + } + + + + // FIT TO SPECIAL FUNCTIONS + // Fit to a Poisson distribution + public void poisson(){ + this.userSupplied = false; + this.fitPoisson(0); + } + + // Fit to a Poisson distribution + public void poissonPlot(){ + this.userSupplied = false; + this.fitPoisson(1); + } + + protected void fitPoisson(int plotFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=6; + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=2; + if(!this.scaleFlag)this.nTerms=2; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // Check all abscissae are integers + for(int i=0; i<this.nData; i++){ + if(xData[0][i]-Math.floor(xData[0][i])!=0.0D)throw new IllegalArgumentException("all abscissae must be, mathematically, integer values"); + } + + // Calculate x value at peak y (estimate of the distribution mode) + ArrayList<Object> ret1 = Regression.dataSign(yData); + Double tempd = null; + Integer tempi = null; + tempi = (Integer)ret1.get(5); + int peaki = tempi.intValue(); + double mean = xData[0][peaki]; + + // Calculate peak value + tempd = (Double)ret1.get(4); + double peak = tempd.doubleValue(); + + // Fill arrays needed by the Simplex + double[] start = new double[this.nTerms]; + double[] step = new double[this.nTerms]; + start[0] = mean; + if(this.scaleFlag){ + start[1] = peak/(Math.exp(mean*Math.log(mean)-Stat.logFactorial(mean))*Math.exp(-mean)); + } + step[0] = 0.1D*start[0]; + if(step[0]==0.0D){ + ArrayList<Object> ret0 = Regression.dataSign(xData[0]); + Double tempdd = null; + tempdd = (Double)ret0.get(2); + double xmax = tempdd.doubleValue(); + if(xmax==0.0D){ + tempdd = (Double)ret0.get(0); + xmax = tempdd.doubleValue(); + } + step[0]=xmax*0.1D; + } + if(this.scaleFlag)step[1] = 0.1D*start[1]; + + // Nelder and Mead Simplex Regression + PoissonFunction f = new PoissonFunction(); + this.addConstraint(1,-1,0.0D); + f.scaleOption = this.scaleFlag; + f.scaleFactor = this.yScaleFactor; + + Object regFun2 = (Object) f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + // Plot results + this.plotOpt=false; + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + } + + + // FIT TO A NORMAL (GAUSSIAN) DISTRIBUTION + + // Fit to a Gaussian + public void gaussian(){ + this.userSupplied = false; + this.fitGaussian(0); + } + + public void normal(){ + this.userSupplied = false; + this.fitGaussian(0); + } + + // Fit to a Gaussian + public void gaussianPlot(){ + this.userSupplied = false; + this.fitGaussian(1); + } + + // Fit to a Gaussian + public void normalPlot(){ + this.userSupplied = false; + this.fitGaussian(1); + } + + // Fit data to a Gaussian (normal) probability function + protected void fitGaussian(int plotFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=4; + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=3; + if(!this.scaleFlag)this.nTerms=2; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // check sign of y data + Double tempd=null; + ArrayList<Object> retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + double yPeak = tempd.doubleValue(); + boolean yFlag = false; + if(yPeak<0.0D){ + System.out.println("Regression.fitGaussian(): This implementation of the Gaussian distribution takes only positive y values\n(noise taking low values below zero are allowed)"); + System.out.println("All y values have been multiplied by -1 before fitting"); + for(int i =0; i<this.nData; i++){ + yData[i] = -yData[i]; + } + retY = Regression.dataSign(yData); + yFlag=true; + } + + // Calculate x value at peak y (estimate of the Gaussian mean) + ArrayList<Object> ret1 = Regression.dataSign(yData); + Integer tempi = null; + tempi = (Integer)ret1.get(5); + int peaki = tempi.intValue(); + double mean = xData[0][peaki]; + + // Calculate an estimate of the sd + double sd = Math.sqrt(2.0D)*halfWidth(xData[0], yData); + + // Calculate estimate of y scale + tempd = (Double)ret1.get(4); + double ym = tempd.doubleValue(); + ym=ym*sd*Math.sqrt(2.0D*Math.PI); + + // Fill arrays needed by the Simplex + double[] start = new double[this.nTerms]; + double[] step = new double[this.nTerms]; + start[0] = mean; + start[1] = sd; + if(this.scaleFlag){ + start[2] = ym; + } + step[0] = 0.1D*sd; + step[1] = 0.1D*start[1]; + if(step[1]==0.0D){ + ArrayList<Object> ret0 = Regression.dataSign(xData[0]); + Double tempdd = null; + tempdd = (Double)ret0.get(2); + double xmax = tempdd.doubleValue(); + if(xmax==0.0D){ + tempdd = (Double)ret0.get(0); + xmax = tempdd.doubleValue(); + } + step[0]=xmax*0.1D; + } + if(this.scaleFlag)step[2] = 0.1D*start[1]; + + // Nelder and Mead Simplex Regression + GaussianFunction f = new GaussianFunction(); + this.addConstraint(1,-1, 0.0D); + f.scaleOption = this.scaleFlag; + f.scaleFactor = this.yScaleFactor; + + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + if(yFlag){ + // restore data + for(int i=0; i<this.nData-1; i++){ + this.yData[i]=-this.yData[i]; + } + } + + } + + // Fit data to a Gaussian (normal) probability function + // with option to fix some of the parameters + // parameter order - mean, sd, scale factor + public void gaussian(double[] initialEstimates, boolean[] fixed){ + this.userSupplied = true; + this.fitGaussianFixed(initialEstimates, fixed, 0); + } + + // Fit to a Gaussian + // with option to fix some of the parameters + // parameter order - mean, sd, scale factor + public void normal(double[] initialEstimates, boolean[] fixed){ + this.userSupplied = true; + this.fitGaussianFixed(initialEstimates, fixed, 0); + } + + // Fit to a Gaussian + // with option to fix some of the parameters + // parameter order - mean, sd, scale factor + public void gaussianPlot(double[] initialEstimates, boolean[] fixed){ + this.userSupplied = true; + this.fitGaussianFixed(initialEstimates, fixed, 1); + } + + // Fit to a Gaussian + // with option to fix some of the parameters + // parameter order - mean, sd, scale factor + public void normalPlot(double[] initialEstimates, boolean[] fixed){ + this.userSupplied = true; + this.fitGaussianFixed(initialEstimates, fixed, 1); + } + + + // Fit data to a Gaussian (normal) probability function + // with option to fix some of the parameters + // parameter order - mean, sd, scale factor + protected void fitGaussianFixed(double[] initialEstimates, boolean[] fixed, int plotFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=38; + this.values = initialEstimates; + this.fixed = fixed; + this.scaleFlag=true; + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=3; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // check sign of y data + Double tempd=null; + ArrayList<Object> retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + double yPeak = tempd.doubleValue(); + boolean yFlag = false; + if(yPeak<0.0D){ + System.out.println("Regression.fitGaussian(): This implementation of the Gaussian distribution takes only positive y values\n(noise taking low values below zero are allowed)"); + System.out.println("All y values have been multiplied by -1 before fitting"); + for(int i =0; i<this.nData; i++){ + yData[i] = -yData[i]; + } + retY = Regression.dataSign(yData); + yFlag=true; + } + + // Create instance of GaussianFunctionFixed + GaussianFunctionFixed f = new GaussianFunctionFixed(); + f.fixed = fixed; + f.param = initialEstimates; + + // Determine unknowns + int nT = this.nTerms; + for(int i=0; i<this.nTerms; i++)if(fixed[i])nT--; + if(nT==0){ + if(plotFlag==0){ + throw new IllegalArgumentException("At least one parameter must be available for variation by the Regression procedure or GauasianPlot should have been called and not Gaussian"); + } + else{ + plotFlag = 3; + } + } + + double[] start = new double[nT]; + double[] step = new double[nT]; + boolean[] constraint = new boolean[nT]; + + // Fill arrays needed by the Simplex + double xMin = Fmath.minimum(xData[0]); + double xMax = Fmath.maximum(xData[0]); + double yMax = Fmath.maximum(yData); + if(initialEstimates[2]==0.0D){ + if(fixed[2]){ + throw new IllegalArgumentException("Scale factor has been fixed at zero"); + } + else{ + initialEstimates[2] = yMax; + } + } + int ii = 0; + for(int i=0; i<this.nTerms; i++){ + if(!fixed[i]){ + start[ii] = initialEstimates[i]; + step[ii] = start[ii]*0.1D; + if(step[ii]==0.0D)step[ii] = (xMax - xMin)*0.1D; + constraint[ii] = false; + if(i==1)constraint[ii] = true; + ii++; + } + } + this.nTerms = nT; + + // Nelder and Mead Simplex Regression + for(int i=0; i<this.nTerms; i++){ + if(constraint[i])this.addConstraint(i,-1, 0.0D); + } + Object regFun2 = (Object)f; + if(plotFlag!=3)this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + if(plotFlag==3){ + // Plot results + int flag = this.plotXYfixed(regFun2, "Gaussian distribution - all parameters fixed"); + } + + if(yFlag){ + // restore data + for(int i=0; i<this.nData-1; i++){ + this.yData[i]=-this.yData[i]; + } + } + + } + + // FIT TO LOG-NORMAL DISTRIBUTIONS (TWO AND THREE PARAMETERS) + + // TWO PARAMETER LOG-NORMAL DISTRIBUTION + // Fit to a two parameter log-normal distribution + public void logNormal(){ + this.fitLogNormalTwoPar(0); + } + + public void logNormalTwoPar(){ + this.fitLogNormalTwoPar(0); + } + + // Fit to a two parameter log-normal distribution and plot result + public void logNormalPlot(){ + this.fitLogNormalTwoPar(1); + } + + public void logNormalTwoParPlot(){ + this.fitLogNormalTwoPar(1); + } + + // Fit data to a two parameterlog-normal probability function + protected void fitLogNormalTwoPar(int plotFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=36; + this.userSupplied = false; + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=3; + if(!this.scaleFlag)this.nTerms=2; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // check sign of y data + Double tempd=null; + ArrayList<Object> retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + double yPeak = tempd.doubleValue(); + boolean yFlag = false; + if(yPeak<0.0D){ + System.out.println("Regression.fitLogNormalTwoPar(): This implementation of the two parameter log-nprmal distribution takes only positive y values\n(noise taking low values below zero are allowed)"); + System.out.println("All y values have been multiplied by -1 before fitting"); + for(int i =0; i<this.nData; i++){ + yData[i] = -yData[i]; + } + retY = Regression.dataSign(yData); + yFlag=true; + } + + // Calculate x value at peak y + ArrayList<Object> ret1 = Regression.dataSign(yData); + Integer tempi = null; + tempi = (Integer)ret1.get(5); + int peaki = tempi.intValue(); + double mean = xData[0][peaki]; + + // Calculate an estimate of the mu + double mu = 0.0D; + for(int i=0; i<this.nData; i++)mu += Math.log(xData[0][i]); + mu /= this.nData; + + // Calculate estimate of sigma + double sigma = 0.0D; + for(int i=0; i<this.nData; i++)sigma += Fmath.square(Math.log(xData[0][i]) - mu); + sigma = Math.sqrt(sigma/this.nData); + + // Calculate estimate of y scale + tempd = (Double)ret1.get(4); + double ym = tempd.doubleValue(); + ym=ym*Math.exp(mu - sigma*sigma/2); + + // Fill arrays needed by the Simplex + double[] start = new double[this.nTerms]; + double[] step = new double[this.nTerms]; + start[0] = mu; + start[1] = sigma; + if(this.scaleFlag){ + start[2] = ym; + } + step[0] = 0.1D*start[0]; + step[1] = 0.1D*start[1]; + if(step[0]==0.0D){ + ArrayList<Object> ret0 = Regression.dataSign(xData[0]); + Double tempdd = null; + tempdd = (Double)ret0.get(2); + double xmax = tempdd.doubleValue(); + if(xmax==0.0D){ + tempdd = (Double)ret0.get(0); + xmax = tempdd.doubleValue(); + } + step[0]=xmax*0.1D; + } + if(step[0]==0.0D){ + ArrayList<Object> ret0 = Regression.dataSign(xData[0]); + Double tempdd = null; + tempdd = (Double)ret0.get(2); + double xmax = tempdd.doubleValue(); + if(xmax==0.0D){ + tempdd = (Double)ret0.get(0); + xmax = tempdd.doubleValue(); + } + step[1]=xmax*0.1D; + } + if(this.scaleFlag)step[2] = 0.1D*start[2]; + + // Nelder and Mead Simplex Regression + LogNormalTwoParFunction f = new LogNormalTwoParFunction(); + this.addConstraint(1,-1,0.0D); + f.scaleOption = this.scaleFlag; + f.scaleFactor = this.yScaleFactor; + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + if(yFlag){ + // restore data + for(int i=0; i<this.nData-1; i++){ + this.yData[i]=-this.yData[i]; + } + } + } + + + // THREE PARAMETER LOG-NORMAL DISTRIBUTION + // Fit to a three parameter log-normal distribution + public void logNormalThreePar(){ + this.fitLogNormalThreePar(0); + } + + // Fit to a three parameter log-normal distribution and plot result + public void logNormalThreeParPlot(){ + this.fitLogNormalThreePar(1); + } + + // Fit data to a three parameter log-normal probability function + protected void fitLogNormalThreePar(int plotFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=37; + this.userSupplied = false; + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=4; + if(!this.scaleFlag)this.nTerms=3; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // check sign of y data + Double tempd=null; + ArrayList<Object> retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + double yPeak = tempd.doubleValue(); + boolean yFlag = false; + if(yPeak<0.0D){ + System.out.println("Regression.fitLogNormalThreePar(): This implementation of the three parameter log-normal distribution takes only positive y values\n(noise taking low values below zero are allowed)"); + System.out.println("All y values have been multiplied by -1 before fitting"); + for(int i =0; i<this.nData; i++){ + yData[i] = -yData[i]; + } + retY = Regression.dataSign(yData); + yFlag=true; + } + + // Calculate x value at peak y + ArrayList<Object> ret1 = Regression.dataSign(yData); + Integer tempi = null; + tempi = (Integer)ret1.get(5); + int peaki = tempi.intValue(); + double mean = xData[0][peaki]; + + // Calculate an estimate of the gamma + double gamma = 0.0D; + for(int i=0; i<this.nData; i++)gamma += xData[0][i]; + gamma /= this.nData; + + // Calculate estimate of beta + double beta = 0.0D; + for(int i=0; i<this.nData; i++)beta += Fmath.square(Math.log(xData[0][i]) - Math.log(gamma)); + beta = Math.sqrt(beta/this.nData); + + // Calculate estimate of alpha + ArrayList<Object> ret0 = Regression.dataSign(xData[0]); + Double tempdd = null; + tempdd = (Double)ret0.get(0); + double xmin = tempdd.doubleValue(); + tempdd = (Double)ret0.get(2); + double xmax = tempdd.doubleValue(); + double alpha = xmin - (xmax - xmin)/100.0D;; + if(xmin==0.0D)alpha -= (xmax - xmin)/100.0D; + + + // Calculate estimate of y scale + tempd = (Double)ret1.get(4); + double ym = tempd.doubleValue(); + ym=ym*(gamma+alpha)*Math.exp(- beta*beta/2); + + // Fill arrays needed by the Simplex + double[] start = new double[this.nTerms]; + double[] step = new double[this.nTerms]; + start[0] = alpha; + start[1] = beta; + start[2] = gamma; + if(this.scaleFlag){ + start[3] = ym; + } + step[0] = 0.1D*start[0]; + step[1] = 0.1D*start[1]; + step[2] = 0.1D*start[2]; + for(int i=0; i<3; i++){ + if(step[i]==0.0D)step[i]=xmax*0.1D; + } + if(this.scaleFlag)step[3] = 0.1D*start[3]; + + // Nelder and Mead Simplex Regression + LogNormalThreeParFunction f = new LogNormalThreeParFunction(); + this.addConstraint(0,+1,xmin); + this.addConstraint(1,-1,0.0D); + this.addConstraint(2,-1,0.0D); + + f.scaleOption = this.scaleFlag; + f.scaleFactor = this.yScaleFactor; + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + if(yFlag){ + // restore data + for(int i=0; i<this.nData-1; i++){ + this.yData[i]=-this.yData[i]; + } + } + } + + + // FIT TO A LORENTZIAN DISTRIBUTION + + // Fit data to a lorentzian + public void lorentzian(){ + this.fitLorentzian(0); + } + + public void lorentzianPlot(){ + this.fitLorentzian(1); + } + + protected void fitLorentzian(int allTest){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=5; + this.userSupplied = false; + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=3; + if(!this.scaleFlag)this.nTerms=2; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // check sign of y data + Double tempd=null; + ArrayList<Object> retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + double yPeak = tempd.doubleValue(); + boolean yFlag = false; + if(yPeak<0.0D){ + System.out.println("Regression.fitLorentzian(): This implementation of the Lorentzian distribution takes only positive y values\n(noise taking low values below zero are allowed)"); + System.out.println("All y values have been multiplied by -1 before fitting"); + for(int i =0; i<this.nData; i++){ + yData[i] = -yData[i]; + } + retY = Regression.dataSign(yData); + yFlag=true; + } + + // Calculate x value at peak y (estimate of the distribution mode) + ArrayList ret1 = Regression.dataSign(yData); + Integer tempi = null; + tempi = (Integer)ret1.get(5); + int peaki = tempi.intValue(); + double mean = xData[0][peaki]; + + // Calculate an estimate of the half-height width + double sd = halfWidth(xData[0], yData); + + // Calculate estimate of y scale + tempd = (Double)ret1.get(4); + double ym = tempd.doubleValue(); + ym=ym*sd*Math.PI/2.0D; + + // Fill arrays needed by the Simplex + double[] start = new double[this.nTerms]; + double[] step = new double[this.nTerms]; + start[0] = mean; + start[1] = sd*0.9D; + if(this.scaleFlag){ + start[2] = ym; + } + step[0] = 0.2D*sd; + if(step[0]==0.0D){ + ArrayList<Object> ret0 = Regression.dataSign(xData[0]); + Double tempdd = null; + tempdd = (Double)ret0.get(2); + double xmax = tempdd.doubleValue(); + if(xmax==0.0D){ + tempdd = (Double)ret0.get(0); + xmax = tempdd.doubleValue(); + } + step[0]=xmax*0.1D; + } + step[1] = 0.2D*start[1]; + if(this.scaleFlag)step[2] = 0.2D*start[2]; + + // Nelder and Mead Simplex Regression + LorentzianFunction f = new LorentzianFunction(); + this.addConstraint(1,-1,0.0D); + f.scaleOption = this.scaleFlag; + f.scaleFactor = this.yScaleFactor; + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(allTest==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + if(yFlag){ + // restore data + for(int i=0; i<this.nData-1; i++){ + this.yData[i]=-this.yData[i]; + } + } + + } + + + // Static method allowing fitting of a data array to one or several of the above distributions + public static void fitOneOrSeveralDistributions(double[] array){ + + int numberOfPoints = array.length; // number of points + double maxValue = Fmath.maximum(array); // maximum value of distribution + double minValue = Fmath.minimum(array); // minimum value of distribution + double span = maxValue - minValue; // span of distribution + + // Calculation of number of bins and bin width + int numberOfBins = (int)Math.ceil(Math.sqrt(numberOfPoints)); + double binWidth = span/numberOfBins; + double averagePointsPerBin = (double)numberOfPoints/(double)numberOfBins; + + // Option for altering bin width + String comment = "Maximum value: " + maxValue + "\n"; + comment += "Minimum value: " + minValue + "\n"; + comment += "Suggested bin width: " + binWidth + "\n"; + comment += "Giving an average points per bin: " + averagePointsPerBin + "\n"; + comment += "If you wish to change the bin width enter the new value below \n"; + comment += "and click on OK\n"; + comment += "If you do NOT wish to change the bin width simply click on OK"; + binWidth = Db.readDouble(comment, binWidth); + + // Create output file + comment = "Input the name of the output text file\n"; + comment += "[Do not forget the extension, e.g. .txt]"; + String outputTitle = Db.readLine(comment, "fitOneOrSeveralDistributionsOutput.txt"); + FileOutput fout = new FileOutput(outputTitle, 'n'); + fout.println("Fitting a set of data to one or more distributions"); + fout.println("Class Regression/Stat: method fitAllDistributions"); + fout.dateAndTimeln(); + fout.println(); + fout.printtab("Number of points: "); + fout.println(numberOfPoints); + fout.printtab("Minimum value: "); + fout.println(minValue); + fout.printtab("Maximum value: "); + fout.println(maxValue); + fout.printtab("Number of bins: "); + fout.println(numberOfBins); + fout.printtab("Bin width: "); + fout.println(binWidth); + fout.printtab("Average number of points per bin: "); + fout.println(averagePointsPerBin); + fout.println(); + + // Choose distributions and perform regression + String[] comments = {"Gaussian Distribution", "Two parameter Log-normal Distribution", "Three parameter Log-normal Distribution", "Logistic Distribution", "Lorentzian Distribution", "Type 1 Extreme Distribution - Gumbel minimum order statistic", "Type 1 Extreme Distribution - Gumbel maximum order statistic", "Type 2 Extreme Distribution - Frechet", "Type 3 Extreme Distribution - Weibull", "Type 3 Extreme Distribution - Exponential Distribution", "Type 3 Extreme Distribution - Rayleigh Distribution", "Pareto Distribution", "Beta Distribution", "Gamma Distribution", "Erlang Distribution", "exit"}; + String[] boxTitles = {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "exit"}; + String headerComment = "Choose next distribution to be fitted by clicking on box number"; + int defaultBox = 1; + boolean testDistType = true; + Regression reg = null; + double[] coeff = null; + while(testDistType){ + int opt = Db.optionBox(headerComment, comments, boxTitles, defaultBox); + switch(opt){ + case 1: // Gaussian + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.gaussianPlot(); + coeff = reg.getCoeff(); + fout.println("NORMAL (GAUSSIAN) DISTRIBUTION"); + fout.println("Best Estimates:"); + fout.printtab("Mean [mu] "); + fout.println(coeff[0]); + fout.printtab("Standard deviation [sigma] "); + fout.println(coeff[1]); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[2]); + Regression.regressionDetails(fout, reg); + break; + case 2: // Two parameter Log-normal + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.logNormalTwoParPlot(); + coeff = reg.getCoeff(); + fout.println("LOG-NORMAL DISTRIBUTION (two parameter statistic)"); + fout.println("Best Estimates:"); + fout.printtab("Location parameter [mu] "); + fout.println(coeff[0]); + fout.printtab("Shape parameter [sigma] "); + fout.println(coeff[1]); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[2]); + Regression.regressionDetails(fout, reg); + break; + case 3: // Three parameter Log-normal + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.logNormalThreeParPlot(); + coeff = reg.getCoeff(); + fout.println("LOG-NORMAL DISTRIBUTION (three parameter statistic)"); + fout.println("Best Estimates:"); + fout.printtab("Location parameter [alpha] "); + fout.println(coeff[0]); + fout.printtab("Shape parameter [beta] "); + fout.println(coeff[1]); + fout.printtab("Scale parameter [gamma] "); + fout.println(coeff[2]); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[3]); + Regression.regressionDetails(fout, reg); + break; + case 4: // Logistic + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.logisticPlot(); + coeff = reg.getCoeff(); + fout.println("LOGISTIC DISTRIBUTION"); + fout.println("Best Estimates:"); + fout.printtab("Location parameter [mu] "); + fout.println(coeff[0]); + fout.printtab("Scale parameter [beta] "); + fout.println(coeff[1]); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[2]); + Regression.regressionDetails(fout, reg); + break; + case 5: // Lorentzian + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.lorentzianPlot(); + coeff = reg.getCoeff(); + fout.println("LORENTZIAN DISTRIBUTION"); + fout.println("Best Estimates:"); + fout.printtab("Mean [mu] "); + fout.println(coeff[0]); + fout.printtab("Half-height parameter [Gamma] "); + fout.println(coeff[1]); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[2]); + Regression.regressionDetails(fout, reg); + break; + case 6: // Gumbel [minimum] + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.gumbelMinPlot(); + coeff = reg.getCoeff(); + fout.println("TYPE 1 (GUMBEL) EXTREME DISTRIBUTION [MINIMUM ORDER STATISTIC]"); + fout.println("Best Estimates:"); + fout.printtab("Location parameter [mu] "); + fout.println(coeff[0]); + fout.printtab("Scale parameter [sigma] "); + fout.println(coeff[1]); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[2]); + Regression.regressionDetails(fout, reg); + break; + case 7: // Gumbel [maximum] + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.gumbelMaxPlot(); + coeff = reg.getCoeff(); + fout.println("TYPE 1 (GUMBEL) EXTREME DISTRIBUTION [MAXIMUM ORDER STATISTIC]"); + fout.println("Best Estimates:"); + fout.printtab("Location parameter [mu] "); + fout.println(coeff[0]); + fout.printtab("Scale parameter [sigma] "); + fout.println(coeff[1]); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[2]); + Regression.regressionDetails(fout, reg); + break; + case 8: // Frechet + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.frechetPlot(); + coeff = reg.getCoeff(); + fout.println("TYPE 2 (FRECHET) EXTREME DISTRIBUTION"); + fout.println("Best Estimates:"); + fout.printtab("Location parameter [mu] "); + fout.println(coeff[0]); + fout.printtab("Scale parameter [sigma] "); + fout.println(coeff[1]); + fout.printtab("Shape parameter [gamma] "); + fout.println(coeff[2]); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[3]); + Regression.regressionDetails(fout, reg); + break; + case 9: // Weibull + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.weibullPlot(); + coeff = reg.getCoeff(); + fout.println("TYPE 3 (WEIBULL) EXTREME DISTRIBUTION"); + fout.println("Best Estimates:"); + fout.printtab("Location parameter [mu] "); + fout.println(coeff[0]); + fout.printtab("Scale parameter [sigma] "); + fout.println(coeff[1]); + fout.printtab("Shape parameter [gamma] "); + fout.println(coeff[2]); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[3]); + Regression.regressionDetails(fout, reg); + break; + case 10: // Exponential + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.exponentialPlot(); + coeff = reg.getCoeff(); + fout.println("EXPONENTIAL DISTRIBUTION"); + fout.println("Best Estimates:"); + fout.printtab("Location parameter [mu] "); + fout.println(coeff[0]); + fout.printtab("Scale parameter [sigma] "); + fout.println(coeff[1]); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[2]); + Regression.regressionDetails(fout, reg); + break; + case 11: // Rayleigh + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.rayleighPlot(); + coeff = reg.getCoeff(); + fout.println("RAYLEIGH DISTRIBUTION"); + fout.println("Best Estimates:"); + fout.printtab("Scale parameter [beta] "); + fout.println(coeff[0]); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[1]); + Regression.regressionDetails(fout, reg); + break; + case 12: // Pareto + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.paretoThreeParPlot(); + coeff = reg.getCoeff(); + fout.println("PARETO DISTRIBUTION"); + fout.println("Best Estimates:"); + fout.printtab("Shape parameter [alpha] "); + fout.println(coeff[0]); + fout.printtab("Scale parameter [beta] "); + fout.println(coeff[1]); + fout.printtab("Threshold parameter [theta] "); + fout.println(coeff[2]); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[3]); + Regression.regressionDetails(fout, reg); + break; + case 13: // Beta + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.betaMinMaxPlot(); + coeff = reg.getCoeff(); + fout.println("BETA DISTRIBUTION"); + fout.println("Best Estimates:"); + fout.printtab("Shape parameter [alpha] "); + fout.println(coeff[0]); + fout.printtab("Shape parameter [beta] "); + fout.println(coeff[1]); + fout.printtab("minimum limit [min] "); + fout.println(coeff[2]); + fout.printtab("maximum limit [max] "); + fout.println(coeff[3]); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[4]); + Regression.regressionDetails(fout, reg); + break; + case 14: // Gamma + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.gammaPlot(); + coeff = reg.getCoeff(); + fout.println("GAMMA DISTRIBUTION"); + fout.println("Best Estimates:"); + fout.printtab("Location parameter [mu] "); + fout.println(coeff[0]); + fout.printtab("Scale parameter [beta] "); + fout.println(coeff[1]); + fout.printtab("Shape parameter [gamma] "); + fout.println(coeff[2]); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[3]); + Regression.regressionDetails(fout, reg); + break; + case 15: // Erlang + reg = new Regression(array, binWidth); + reg.supressPrint(); + reg.erlangPlot(); + coeff = reg.getCoeff(); + fout.println("ERLANG DISTRIBUTION"); + fout.println("Best Estimates:"); + fout.printtab("Shape parameter [lambda] "); + fout.println(coeff[0]); + fout.printtab("Rate parameter [k] "); + fout.println(reg.getKayValue()); + fout.printtab("Scaling factor [Ao] "); + fout.println(coeff[1]); + Regression.regressionDetails(fout, reg); + break; + case 16: // exit + default: fout.close(); + testDistType = false; + } + } + } + + // Output method for fitOneOrSeveralDistributions + protected static void regressionDetails(FileOutput fout, Regression reg){ + fout.println(); + fout.println("Regression details:"); + fout.printtab("Chi squared: "); + fout.println(reg.getChiSquare()); + fout.printtab("Reduced chi squared: "); + fout.println(reg.getReducedChiSquare()); + fout.printtab("Sum of squares: "); + fout.println(reg.getSumOfSquares()); + fout.printtab("Degrees of freedom: "); + fout.println(reg.getDegFree()); + fout.printtab("Number of iterations: "); + fout.println(reg.getNiter()); + fout.printtab("maximum number of iterations allowed: "); + fout.println(reg.getNmax()); + fout.println(); + fout.println(); + } + + + // Calculate the multiple correlation coefficient + protected void multCorrelCoeff(double[] yy, double[] yyCalc, double[] ww){ + + // sum of reciprocal weights squared + double sumRecipW = 0.0D; + for(int i=0; i<this.nData; i++){ + sumRecipW += 1.0D/Fmath.square(ww[i]); + } + + // weighted mean of yy + double my = 0.0D; + for(int j=0; j<this.nData; j++){ + my += yy[j]/Fmath.square(ww[j]); + } + my /= sumRecipW; + + + // weighted mean of residuals + double mr = 0.0D; + double[] residuals = new double[this.nData]; + for(int j=0; j<this.nData; j++){ + residuals[j] = yy[j] - yyCalc[j]; + mr += residuals[j]/Fmath.square(ww[j]); + } + mr /= sumRecipW; + + // calculate yy weighted sum of squares + double s2yy = 0.0D; + for(int k=0; k<this.nData; k++){ + s2yy += Fmath.square((yy[k]-my)/ww[k]); + } + + // calculate residual weighted sum of squares + double s2r = 0.0D; + for(int k=0; k<this.nData; k++){ + s2r += Fmath.square((residuals[k]-mr)/ww[k]); + } + + // calculate multiple coefficient of determination + this.sampleR2 = 1.0D - s2r/s2yy; + this.sampleR = Math.sqrt(this.sampleR2); + + // Calculate adjusted multiple coefficient of determination + this.adjustedR2 = ((this.nData - 1)*this.sampleR2 - this.nXarrays)/(this.nData - this.nXarrays - 1 ); + this.adjustedR = Math.sqrt(this.adjustedR2); + + // F-ratio + if(this.nXarrays>1){ + this.multipleF = this.sampleR2*(this.nData-this.nXarrays)/((1.0D-this.sampleR2)*(this.nXarrays-1)); + this.adjustedF = this.adjustedR2*(this.nData-this.nXarrays)/((1.0D-this.adjustedR2)*(this.nXarrays-1)); + } + } + + // Get the Sample Correlation Coefficient + public double getSampleR(){ + return this.sampleR; + } + + // Get the Sample Correlation Coefficient Squared + public double getSampleR2(){ + return this.sampleR2; + } + + // Get the Adjusted Sample Correlation Coefficient + public double getAdjustedR(){ + return this.adjustedR; + } + + // Get the Adjusted Sample Correlation Coefficient Squared + public double getAdjustedR2(){ + return this.adjustedR2; + } + + // Get the Multiple Correlation Coefficient F ratio + public double getMultipleF(){ + if(this.nXarrays==1){ + System.out.println("Regression.getMultipleF - The regression is not a multple regession: NaN returned"); + } + return this.multipleF; + } + + // check data arrays for sign, max, min and peak + protected static ArrayList<Object> dataSign(double[] data){ + + ArrayList<Object> ret = new ArrayList<Object>(); + int n = data.length; + + double max=data[0]; // maximum + int maxi=0; // index of above + double min=data[0]; // minimum + int mini=0; // index of above + double peak=0.0D; // peak: larger of maximum and any abs(negative minimum) + int peaki=-1; // index of above + int signFlag=-1; // 0 all positive; 1 all negative; 2 positive and negative + double shift=0.0D; // shift to make all positive if a mixture of positive and negative + double mean = 0.0D; // mean value + int signCheckZero=0; // number of zero values + int signCheckNeg=0; // number of positive values + int signCheckPos=0; // number of negative values + + for(int i=0; i<n; i++){ + mean =+ data[i]; + if(data[i]>max){ + max=data[i]; + maxi=i; + } + if(data[i]<min){ + min=data[i]; + mini=i; + } + if(data[i]==0.0D)signCheckZero++; + if(data[i]>0.0D)signCheckPos++; + if(data[i]<0.0D)signCheckNeg++; + } + mean /= (double)n; + + if((signCheckZero+signCheckPos)==n){ + peak=max; + peaki=maxi; + signFlag=0; + } + else{ + if((signCheckZero+signCheckNeg)==n){ + peak=min; + peaki=mini; + signFlag=1; + } + else{ + peak=max; + peaki=maxi; + if(-min>max){ + peak=min; + peak=mini; + } + signFlag=2; + shift=-min; + } + } + + // transfer results to the ArrayList + ret.add(new Double(min)); + ret.add(new Integer(mini)); + ret.add(new Double(max)); + ret.add(new Integer(maxi)); + ret.add(new Double(peak)); + ret.add(new Integer(peaki)); + ret.add(new Integer(signFlag)); + ret.add(new Double(shift)); + ret.add(new Double(mean)); + ret.add(new Integer(signCheckZero)); + ret.add(new Integer(signCheckPos)); + ret.add(new Integer(signCheckNeg)); + + + return ret; + } + + public void frechet(){ + this.fitFrechet(0, 0); + } + + public void frechetPlot(){ + this.fitFrechet(1, 0); + } + + public void frechetTwoPar(){ + this.fitFrechet(0, 1); + } + + public void frechetTwoParPlot(){ + this.fitFrechet(1, 1); + } + + public void frechetStandard(){ + this.fitFrechet(0, 2); + } + + public void frechetStandardPlot(){ + this.fitFrechet(1, 2); + } + + protected void fitFrechet(int allTest, int typeFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.userSupplied = false; + switch(typeFlag){ + case 0: this.lastMethod=13; + this.nTerms=4; + break; + case 1: this.lastMethod=14; + this.nTerms=3; + break; + case 2: this.lastMethod=15; + this.nTerms=2; + break; + } + if(!this.scaleFlag)this.nTerms=this.nTerms-1; + this.frechetWeibull=true; + this.fitFrechetWeibull(allTest, typeFlag); + } + + // method for fitting data to either a Frechet or a Weibull distribution + protected void fitFrechetWeibull(int allTest, int typeFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // check y data + Double tempd=null; + ArrayList<Object> retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + double yPeak = tempd.doubleValue(); + Integer tempi = null; + tempi = (Integer)retY.get(5); + int peaki = tempi.intValue(); + tempd = (Double)retY.get(8); + double mean = tempd.doubleValue(); + + // check for infinity + boolean testInf = true; + double dof = this.degreesOfFreedom; + while(testInf){ + if(this.infinityCheck(yPeak, peaki)){ + dof--; + if(dof<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("The effective degrees of freedom have been reduced to zero"); + retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + yPeak = tempd.doubleValue(); + tempi = (Integer)retY.get(5); + peaki = tempi.intValue(); + tempd = (Double)retY.get(8); + mean = tempd.doubleValue(); + } + else{ + testInf = false; + } + } + + // check sign of y data + String ss = "Weibull"; + if(this.frechetWeibull)ss = "Frechet"; + boolean ySignFlag = false; + if(yPeak<0.0D){ + this.reverseYsign(ss); + retY = Regression.dataSign(this.yData); + yPeak = -yPeak; + ySignFlag = true; + } + + // check y values for all very small values + boolean magCheck=false; + double magScale = this.checkYallSmall(yPeak, ss); + if(magScale!=1.0D){ + magCheck=true; + yPeak=1.0D; + } + + // minimum value of x + ArrayList<Object> retX = Regression.dataSign(this.xData[0]); + tempd = (Double)retX.get(0); + double xMin = tempd.doubleValue(); + + // maximum value of x + tempd = (Double)retX.get(2); + double xMax = tempd.doubleValue(); + + // Calculate x value at peak y (estimate of the 'distribution mode') + double distribMode = xData[0][peaki]; + + // Calculate an estimate of the half-height width + double sd = Math.log(2.0D)*halfWidth(xData[0], yData); + + // Save x-y-w data + double[] xx = new double[this.nData]; + double[] yy = new double[this.nData]; + double[] ww = new double[this.nData]; + + for(int i=0; i<this.nData; i++){ + xx[i]=this.xData[0][i]; + yy[i]=this.yData[i]; + ww[i]=this.weight[i]; + } + + // Calculate the cumulative probability and return ordinate scaling factor estimate + double[] cumX = new double[this.nData]; + double[] cumY = new double[this.nData]; + double[] cumW = new double[this.nData]; + ErrorProp[] cumYe = ErrorProp.oneDarray(this.nData); + double yScale = this.calculateCumulativeValues(cumX, cumY, cumW, cumYe, peaki, yPeak, distribMode, ss); + + //Calculate loglog v log transforms + if(this.frechetWeibull){ + for(int i=0; i<this.nData; i++){ + cumYe[i] = ErrorProp.over(1.0D, cumYe[i]); + cumYe[i] = ErrorProp.log(cumYe[i]); + cumYe[i] = ErrorProp.log(cumYe[i]); + cumY[i] = cumYe[i].getValue(); + cumW[i] = cumYe[i].getError(); + } + } + else{ + for(int i=0; i<this.nData; i++){ + cumYe[i] = ErrorProp.minus(1.0D,cumYe[i]); + cumYe[i] = ErrorProp.over(1.0D, cumYe[i]); + cumYe[i] = ErrorProp.log(cumYe[i]); + cumYe[i] = ErrorProp.log(cumYe[i]); + cumY[i] = cumYe[i].getValue(); + cumW[i] = cumYe[i].getError(); + } + } + + // Fill data arrays with transformed data + for(int i =0; i<this.nData; i++){ + xData[0][i] = cumX[i]; + yData[i] = cumY[i]; + weight[i] = cumW[i]; + } + boolean weightOptHold = this.weightOpt; + this.weightOpt=true; + + // Nelder and Mead Simplex Regression for semi-linearised Frechet or Weibull + // disable statistical analysis + boolean statFlagHold = this.statFlag; + this.statFlag=false; + + // Fill arrays needed by the Simplex + double[] start = new double[this.nTerms]; + double[] step = new double[this.nTerms]; + for(int i=0; i<this.nTerms; i++){ + start[i]=1.0D; + step[i]=0.2D; + } + double[] gammamin = null; + double gammat = 0; + switch(typeFlag){ + case 0: + start[0] = xMin - Math.abs(0.1D*xMin); //mu + start[1] = sd; //sigma + start[2] = 4.0; // gamma + // step sizes + step[0] = 0.2D*start[0]; + if(step[0]==0.0D){ + ArrayList<Object> ret0 = Regression.dataSign(xData[0]); + Double tempdd = null; + tempdd = (Double)ret0.get(2); + double xmax = tempdd.doubleValue(); + if(xmax==0.0D){ + tempdd = (Double)ret0.get(0); + xmax = tempdd.doubleValue(); + } + step[0]=xmax*0.1D; + } + step[1] = 0.2D*start[1]; + step[2] = 0.5D*start[2]; + this.addConstraint(0,+1,xMin); + this.addConstraint(1,-1,0.0D); + this.addConstraint(2,-1,0.0D); + break; + case 1: start[0] = sd; //sigma + start[1] = 4.0; // gamma + // step sizes + step[0] = 0.2D*start[0]; + step[1] = 0.5D*start[1]; + this.addConstraint(0,-1,0.0D); + this.addConstraint(1,-1,0.0D); + break; + case 2: start[0] = 4.0; // gamma + // step size + step[0] = 0.5D*start[0]; + this.addConstraint(0,-1,0.0D); + break; + } + + // Create instance of loglog function and perform regression + if(this.frechetWeibull){ + FrechetFunctionTwo f = new FrechetFunctionTwo(); + f.typeFlag = typeFlag; + Object regFun2 = (Object)f; + System.out.println("pppp " + start[0] + " " + start[1] + " " + start[2]); + + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + } + else{ + WeibullFunctionTwo f = new WeibullFunctionTwo(); + f.typeFlag = typeFlag; + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + } + + // Get best estimates of loglog regression + double[] ests = this.best.clone(); + + // Nelder and Mead Simplex Regression for Frechet or Weibull + // using best estimates from loglog regression as initial estimates + + // re-enable statistical analysis if statFlag was set to true + this.statFlag = statFlagHold; + + // restore data reversing the loglog transform but maintaining any sign reversals + this.weightOpt=weightOptHold; + for(int i =0; i<this.nData; i++){ + xData[0][i] = xx[i]; + yData[i] = yy[i]; + weight[i] = ww[i]; + } + + // Fill arrays needed by the Simplex + switch(typeFlag){ + case 0: start[0] = ests[0]; //mu + start[1] = ests[1]; //sigma + start[2] = ests[2]; //gamma + if(this.scaleFlag){ + start[3] = 1.0/yScale; //y axis scaling factor + } + step[0] = 0.1D*start[0]; + if(step[0]==0.0D){ + ArrayList<Object> ret0 = Regression.dataSign(xData[0]); + Double tempdd = null; + tempdd = (Double)ret0.get(2); + double xmax = tempdd.doubleValue(); + if(xmax==0.0D){ + tempdd = (Double)ret0.get(0); + xmax = tempdd.doubleValue(); + } + step[0]=xmax*0.1D; + } + step[1] = 0.1D*start[1]; + step[2] = 0.1D*start[2]; + if(this.scaleFlag){ + step[3] = 0.1D*start[3]; + } + break; + case 1: start[0] = ests[0]; //sigma + start[1] = ests[1]; //gamma + if(this.scaleFlag){ + start[2] = 1.0/yScale; //y axis scaling factor + } + step[0] = 0.1D*start[0]; + step[1] = 0.1D*start[1]; + if(this.scaleFlag)step[2] = 0.1D*start[2]; + break; + case 2: start[0] = ests[0]; //gamma + if(this.scaleFlag){ + start[1] = 1.0/yScale; //y axis scaling factor + } + step[0] = 0.1D*start[0]; + if(this.scaleFlag)step[1] = 0.1D*start[1]; + break; + } + + // Create instance of Frechet function and perform regression + if(this.frechetWeibull){ + FrechetFunctionOne ff = new FrechetFunctionOne(); + ff.typeFlag = typeFlag; + ff.scaleOption = this.scaleFlag; + ff.scaleFactor = this.yScaleFactor; + Object regFun3 = (Object)ff; + this.nelderMead(regFun3, start, step, this.fTol, this.nMax); + if(allTest==1){ + // Print results + if(!this.supressPrint)this.print(); + // Plot results + int flag = this.plotXY(ff); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + } + else{ + WeibullFunctionOne ff = new WeibullFunctionOne(); + ff.typeFlag = typeFlag; + ff.scaleOption = this.scaleFlag; + ff.scaleFactor = this.yScaleFactor; + Object regFun3 = (Object)ff; + this.nelderMead(regFun3, start, step, this.fTol, this.nMax); + if(allTest==1){ + // Print results + if(!this.supressPrint)this.print(); + // Plot results + int flag = this.plotXY(ff); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + } + + // restore data + this.weightOpt = weightOptHold; + if(magCheck){ + for(int i =0; i<this.nData; i++){ + this.yData[i] = yy[i]/magScale; + if(this.weightOpt)this.weight[i] = ww[i]/magScale; + } + } + if(ySignFlag){ + for(int i =0; i<this.nData; i++){ + this.yData[i]=-this.yData[i]; + } + } + } + + // Check for y value = infinity + public boolean infinityCheck(double yPeak, int peaki){ + boolean flag=false; + if(yPeak == 1.0D/0.0D || yPeak == -1.0D/0.0D){ + int ii = peaki+1; + if(peaki==this.nData-1)ii = peaki-1; + this.xData[0][peaki]=this.xData[0][ii]; + this.yData[peaki]=this.yData[ii]; + this.weight[peaki]=this.weight[ii]; + System.out.println("An infinty has been removed at point "+peaki); + flag = true; + } + return flag; + } + + // reverse sign of y values if negative + public void reverseYsign(String ss){ + System.out.println("This implementation of the " + ss + " distributions takes only positive y values\n(noise taking low values below zero are allowed)"); + System.out.println("All y values have been multiplied by -1 before fitting"); + for(int i =0; i<this.nData; i++){ + this.yData[i] = -this.yData[i]; + } + } + + // check y values for all y are very small value + public double checkYallSmall(double yPeak, String ss){ + double magScale = 1.0D; + double recipYpeak = Fmath.truncate(1.0/yPeak, 4); + if(yPeak<1e-4){ + System.out.println(ss + " fitting: The ordinate axis (y axis) has been rescaled by "+recipYpeak+" to reduce rounding errors"); + for(int i=0; i<this.nData; i++){ + this.yData[i]*=recipYpeak; + if(this.weightOpt)this.weight[i]*=recipYpeak; + } + magScale=recipYpeak; + } + return magScale; + } + + // Calculate cumulative values + public double calculateCumulativeValues(double[] cumX, double[] cumY, double[] cumW, ErrorProp[] cumYe, int peaki, double yPeak, double distribMode, String ss){ + cumX[0]= this.xData[0][0]; + for(int i=1; i<this.nData; i++){ + cumX[i] = this.xData[0][i]; + } + + ErrorProp[] yE = ErrorProp.oneDarray(this.nData); + for(int i=0; i<this.nData; i++){ + yE[i].reset(this.yData[i], this.weight[i]); + } + + // check on shape of data for first step of cumulative calculation + if(peaki!=0){ + if(peaki==this.nData-1){ + System.out.println("The data does not cover a wide enough range of x values to fit to a " + ss + " distribution with any accuracy"); + System.out.println("The regression will be attempted but you should treat any result with great caution"); + } + if(this.yData[0]<this.yData[1]*0.5D && this.yData[0]>distribMode*0.02D){ + ErrorProp x0 = new ErrorProp(0.0D, 0.0D); + x0 = yE[0].times(this.xData[0][1]-this.xData[0][0]); + x0 = x0.over(yE[1].minus(yE[0])); + x0 = ErrorProp.minus(this.xData[0][0],x0); + if(this.yData[0]>=0.9D*yPeak)x0=(x0.plus(this.xData[0][0])).over(2.0D); + if(x0.getValue()<0.0D)x0.reset(0.0D, 0.0D); + cumYe[0] = yE[0].over(2.0D); + cumYe[0] = cumYe[0].times(ErrorProp.minus(this.xData[0][0], x0)); + } + else{ + cumYe[0].reset(0.0D, this.weight[0]); + } + } + else{ + cumYe[0].reset(0.0D, this.weight[0]); + + } + + // cumulative calculation for rest of the points (trapezium approximation) + for(int i=1; i<this.nData; i++){ + cumYe[i] = yE[i].plus(yE[i-1]); + cumYe[i] = cumYe[i].over(2.0D); + cumYe[i] = cumYe[i].times(this.xData[0][i]-this.xData[0][i-1]); + cumYe[i] = cumYe[i].plus(cumYe[i-1]); + } + // check on shape of data for final step of cumulative calculation + ErrorProp cumYtotal = cumYe[this.nData-1].copy(); + if(peaki==this.nData-1){ + cumYtotal = cumYtotal.times(2.0D); + } + else{ + if(this.yData[this.nData-1]<yData[this.nData-2]*0.5D && yData[this.nData-1]>distribMode*0.02D){ + ErrorProp xn = new ErrorProp(); + xn = yE[this.nData-1].times(this.xData[0][this.nData-2]-this.xData[0][this.nData-1]); + xn = xn.over(yE[this.nData-2].minus(yE[this.nData-1])); + xn = ErrorProp.minus(this.xData[0][this.nData-1], xn); + if(this.yData[0]>=0.9D*yPeak)xn=(xn.plus(this.xData[0][this.nData-1])).over(2.0D); + cumYtotal = cumYtotal.plus(ErrorProp.times(0.5D,(yE[this.nData-1].times(xn.minus(this.xData[0][this.nData-1]))))); + } + } + // estimate y scaling factor + double yScale = 1.0D/cumYtotal.getValue(); + for(int i=0; i<this.nData; i++){ + cumYe[i]=cumYe[i].over(cumYtotal); + } + + // check for zero and negative values + int jj = 0; + boolean test = true; + for(int i=0; i<this.nData; i++){ + if(cumYe[i].getValue()<=0.0D){ + if(i<=jj){ + test=true; + jj = i; + while(test){ + jj++; + if(jj>=this.nData)throw new ArithmeticException("all zero cumulative data!!"); + if(cumYe[jj].getValue()>0.0D){ + cumYe[i]=cumYe[jj].copy(); + cumX[i]=cumX[jj]; + test=false; + } + } + } + else{ + if(i==this.nData-1){ + cumYe[i]=cumYe[i-1].copy(); + cumX[i]=cumX[i-1]; + } + else{ + cumYe[i]=cumYe[i-1].plus(cumYe[i+1]); + cumYe[i]=cumYe[i].over(2.0D); + cumX[i]=(cumX[i-1]+cumX[i+1])/2.0D; + } + } + } + } + + // check for unity value + jj = this.nData-1; + for(int i=this.nData-1; i>=0; i--){ + if(cumYe[i].getValue()>=1.0D){ + if(i>=jj){ + test=true; + jj = this.nData-1; + while(test){ + jj--; + if(jj<0)throw new ArithmeticException("all unity cumulative data!!"); + if(cumYe[jj].getValue()<1.0D){ + cumYe[i]=cumYe[jj].copy(); + cumX[i]=cumX[jj]; + test=false; + } + } + } + else{ + if(i==0){ + cumYe[i]=cumYe[i+1].copy(); + cumX[i]=cumX[i+1]; + } + else{ + cumYe[i]=cumYe[i-1].plus(cumYe[i+1]); + cumYe[i]=cumYe[i].over(2.0D); + cumX[i]=(cumX[i-1]+cumX[i+1])/2.0D; + } + } + } + } + return yScale; + } + + public void weibull(){ + this.fitWeibull(0, 0); + } + + public void weibullPlot(){ + this.fitWeibull(1, 0); + } + + public void weibullTwoPar(){ + this.fitWeibull(0, 1); + } + + public void weibullTwoParPlot(){ + this.fitWeibull(1, 1); + } + + public void weibullStandard(){ + this.fitWeibull(0, 2); + } + + public void weibullStandardPlot(){ + this.fitWeibull(1, 2); + } + + protected void fitWeibull(int allTest, int typeFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.userSupplied = false; + switch(typeFlag){ + case 0: this.lastMethod=16; + this.nTerms=4; + break; + case 1: this.lastMethod=17; + this.nTerms=3; + break; + case 2: this.lastMethod=18; + this.nTerms=2; + break; + } + if(!this.scaleFlag)this.nTerms=this.nTerms-1; + this.frechetWeibull=false; + this.fitFrechetWeibull(allTest, typeFlag); + } + + public void gumbelMin(){ + this.fitGumbel(0, 0); + } + + public void gumbelMinPlot(){ + this.fitGumbel(1, 0); + } + + public void gumbelMax(){ + this.fitGumbel(0, 1); + } + public void gumbelMaxPlot(){ + this.fitGumbel(1, 1); + } + + public void gumbelMinOnePar(){ + this.fitGumbel(0, 2); + } + + public void gumbelMinOneParPlot(){ + this.fitGumbel(1, 2); + } + + public void gumbelMaxOnePar(){ + this.fitGumbel(0, 3); + } + + public void gumbelMaxOneParPlot(){ + this.fitGumbel(1, 3); + } + + public void gumbelMinStandard(){ + this.fitGumbel(0, 4); + } + + public void gumbelMinStandardPlot(){ + this.fitGumbel(1, 4); + } + + public void gumbelMaxStandard(){ + this.fitGumbel(0, 5); + } + + public void gumbelMaxStandardPlot(){ + this.fitGumbel(1, 5); + } + + // No parameters set for estimation + // Correlation coefficient and plot + protected void noParameters(String ss){ + System.out.println(ss+" Regression"); + System.out.println("No parameters set for estimation"); + System.out.println("Theoretical curve obtained"); + String filename1="RegressOutput.txt"; + String filename2="RegressOutputN.txt"; + FileOutput fout = new FileOutput(filename1, 'n'); + System.out.println("Results printed to the file "+filename2); + fout.dateAndTimeln(filename1); + fout.println("No parameters set for estimation"); + switch(this.lastMethod){ + case 11: fout.println("Minimal Standard Gumbel p(x) = exp(x)exp(-exp(x))"); + for(int i=0; i<this.nData; i++)this.yCalc[i]=Math.exp(this.xData[0][i])*Math.exp(-Math.exp(this.xData[0][i])); + break; + case 12: fout.println("Maximal Standard Gumbel p(x) = exp(-x)exp(-exp(-x))"); + for(int i=0; i<this.nData; i++)this.yCalc[i]=Math.exp(-this.xData[0][i])*Math.exp(-Math.exp(-this.xData[0][i])); + break; + case 21: fout.println("Standard Exponential p(x) = exp(-x)"); + for(int i=0; i<this.nData; i++)this.yCalc[i]=Math.exp(-this.xData[0][i]); + break; + } + this.sumOfSquares = 0.0D; + this.chiSquare = 0.0D; + double temp = 0.0D; + for(int i=0; i<this.nData; i++){ + temp = Fmath.square(this.yData[i]-this.yCalc[i]); + this.sumOfSquares += temp; + this.chiSquare += temp/Fmath.square(this.weight[i]); + } + double corrCoeff = Stat.corrCoeff(this.yData, this.yCalc); + fout.printtab("Correlation Coefficient"); + fout.println(Fmath.truncate(corrCoeff, this.prec)); + fout.printtab("Correlation Coefficient Probability"); + fout.println(Fmath.truncate(1.0D-Stat.linearCorrCoeffProb(corrCoeff, this.degreesOfFreedom-1), this.prec)); + + fout.printtab("Sum of Squares"); + fout.println(Fmath.truncate(this.sumOfSquares, this.prec)); + if(this.weightOpt || this.trueFreq){ + fout.printtab("Chi Square"); + fout.println(Fmath.truncate(this.chiSquare, this.prec)); + fout.printtab("chi square probability"); + fout.println(Fmath.truncate(Stat.chiSquareProb(this.chiSquare, this.degreesOfFreedom-1), this.prec)); + } + fout.println(" "); + + fout.printtab("x", this.field); + fout.printtab("p(x) [expl]", this.field); + fout.printtab("p(x) [calc]", this.field); + fout.println("residual"); + + for(int i=0; i<this.nData; i++){ + fout.printtab(Fmath.truncate(this.xData[0][i], this.prec), this.field); + fout.printtab(Fmath.truncate(this.yData[i], this.prec), this.field); + fout.printtab(Fmath.truncate(this.yCalc[i], this.prec), this.field); + fout.println(Fmath.truncate(this.yData[i]-this.yCalc[i], this.prec)); + } + fout.close(); + this.plotXY(); + if(!this.supressYYplot)this.plotYY(); + } + + protected void fitGumbel(int allTest, int typeFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.userSupplied = false; + switch(typeFlag){ + case 0: this.lastMethod=7; + this.nTerms=3; + break; + case 1: this.lastMethod=8; + this.nTerms=3; + break; + case 2: this.lastMethod=9; + this.nTerms=2; + break; + case 3: this.lastMethod=10; + this.nTerms=2; + break; + case 4: this.lastMethod=11; + this.nTerms=1; + break; + case 5: this.lastMethod=12; + this.nTerms=1; + break; + } + if(!this.scaleFlag)this.nTerms=this.nTerms-1; + this.zeroCheck = false; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + if(this.nTerms==0){ + this.noParameters("Gumbel"); + } + else{ + + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // check sign of y data + Double tempd=null; + ArrayList<Object> retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + double yPeak = tempd.doubleValue(); + boolean yFlag = false; + + if(yPeak<0.0D){ + System.out.println("Regression.fitGumbel(): This implementation of the Gumbel distribution takes only positive y values\n(noise taking low values below zero are allowed)"); + System.out.println("All y values have been multiplied by -1 before fitting"); + for(int i =0; i<this.nData; i++){ + yData[i] = -yData[i]; + } + retY = Regression.dataSign(yData); + yFlag=true; + } + + // check x data + ArrayList<Object> retX = Regression.dataSign(xData[0]); + Integer tempi = null; + + // Calculate x value at peak y (estimate of the 'distribution mode') + tempi = (Integer)retY.get(5); + int peaki = tempi.intValue(); + double distribMode = xData[0][peaki]; + + // Calculate an estimate of the half-height width + double sd = halfWidth(xData[0], yData); + + // Nelder and Mead Simplex Regression for Gumbel + // Fill arrays needed by the Simplex + double[] start = new double[this.nTerms]; + double[] step = new double[this.nTerms]; + switch(typeFlag){ + case 0: + case 1: + start[0] = distribMode; //mu + start[1] = sd*Math.sqrt(6.0D)/Math.PI; //sigma + if(this.scaleFlag){ + start[2] = yPeak*start[1]*Math.exp(1); //y axis scaling factor + } + step[0] = 0.1D*start[0]; + if(step[0]==0.0D){ + ArrayList<Object> ret0 = Regression.dataSign(xData[0]); + Double tempdd = null; + tempdd = (Double)ret0.get(2); + double xmax = tempdd.doubleValue(); + if(xmax==0.0D){ + tempdd = (Double)ret0.get(0); + xmax = tempdd.doubleValue(); + } + step[0]=xmax*0.1D; + } + step[1] = 0.1D*start[1]; + if(this.scaleFlag)step[2] = 0.1D*start[2]; + + // Add constraints + this.addConstraint(1,-1,0.0D); + break; + case 2: + case 3: + start[0] = sd*Math.sqrt(6.0D)/Math.PI; //sigma + if(this.scaleFlag){ + start[1] = yPeak*start[0]*Math.exp(1); //y axis scaling factor + } + step[0] = 0.1D*start[0]; + if(this.scaleFlag)step[1] = 0.1D*start[1]; + // Add constraints + this.addConstraint(0,-1,0.0D); + break; + case 4: + case 5: + if(this.scaleFlag){ + start[0] = yPeak*Math.exp(1); //y axis scaling factor + step[0] = 0.1D*start[0]; + } + break; + } + + // Create instance of Gumbel function + GumbelFunction ff = new GumbelFunction(); + + // Set minimum type / maximum type option + ff.typeFlag = typeFlag; + + // Set ordinate scaling option + ff.scaleOption = this.scaleFlag; + ff.scaleFactor = this.yScaleFactor; + + if(typeFlag<4){ + + // Perform simplex regression + Object regFun3 = (Object)ff; + this.nelderMead(regFun3, start, step, this.fTol, this.nMax); + + if(allTest==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(ff); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + } + else{ + // calculate exp exp term + double[][] xxx = new double[1][this.nData]; + double aa=1.0D; + if(typeFlag==5)aa=-1.0D; + for(int i=0; i<this.nData; i++){ + xxx[0][i]=Math.exp(aa*this.xData[0][i])*Math.exp(-Math.exp(aa*this.xData[0][i])); + } + + // perform linear regression + this.linNonLin = true; + this.generalLinear(xxx); + + if(!this.supressPrint)this.print(); + if(!this.supressYYplot)this.plotYY(); + this.plotXY(); + + this.linNonLin = false; + + } + + if(yFlag){ + // restore data + for(int i=0; i<this.nData-1; i++){ + this.yData[i]=-this.yData[i]; + } + } + } + } + + // sort elements x, y and w arrays of doubles into ascending order of the x array + // using selection sort method + protected static void sort(double[] x, double[] y, double[] w){ + int index = 0; + int lastIndex = -1; + int n = x.length; + double holdx = 0.0D; + double holdy = 0.0D; + double holdw = 0.0D; + + while(lastIndex < n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(x[i]<x[index]){ + index=i; + } + } + lastIndex++; + holdx=x[index]; + x[index]=x[lastIndex]; + x[lastIndex]=holdx; + holdy=y[index]; + y[index]=y[lastIndex]; + y[lastIndex]=holdy; + holdw=w[index]; + w[index]=w[lastIndex]; + w[lastIndex]=holdw; + } + } + + // returns estimate of half-height width + protected static double halfWidth(double[] xData, double[] yData){ + double ymax = yData[0]; + int imax = 0; + int n = xData.length; + + for(int i=1; i<n; i++){ + if(yData[i]>ymax){ + ymax=yData[i]; + imax=i; + } + } + ymax /= 2.0D; + + double halflow=-1.0D; + double temp = -1.0D; + int ihl=-1; + if(imax>0){ + ihl=imax-1; + halflow=Math.abs(ymax-yData[ihl]); + for(int i=imax-2; i>=0; i--){ + temp=Math.abs(ymax-yData[i]); + if(temp<halflow){ + halflow=temp; + ihl=i; + } + } + halflow=Math.abs(xData[ihl]-xData[imax]); + } + + double halfhigh=-1.0D; + temp = -1.0D; + int ihh=-1; + if(imax<n-1){ + ihh=imax+1; + halfhigh=Math.abs(ymax-yData[ihh]); + for(int i=imax+2; i<n; i++){ + temp=Math.abs(ymax-yData[i]); + if(temp<halfhigh){ + halfhigh=temp; + ihh=i; + } + } + halfhigh=Math.abs(xData[ihh]-xData[imax]); + } + + double halfw = 0.0D; + int nd = 0; + if(ihl!=-1){ + halfw += halflow; + nd++; + } + if(ihh!=-1){ + halfw += halfhigh; + nd++; + } + halfw /= nd; + + return halfw; + } + + // FIT TO A SIMPLE EXPOPNENTIAL + + // method for fitting data to a simple exponential + public void exponentialSimple(){ + fitsexponentialSimple(0); + } + + // method for fitting data to a simple exponential + public void exponentialSimplePlot(){ + fitsexponentialSimple(1); + } + + // method for fitting data to a simple exponential + protected void fitsexponentialSimple(int plotFlag){ + + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=43; + this.userSupplied = false; + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=2; + if(!this.scaleFlag)this.nTerms=1; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // Estimate of yscale and A - linear transform + int nLen = this.yData.length; + int nLin = nLen; + boolean[] zeros = new boolean[nLen]; + for(int i=0; i<nLen; i++){ + zeros[i] = true; + if(this.xData[0][i]<=0.0D||this.yData[i]<=0.0D){ + zeros[i] = false; + nLin--; + } + } + double[] xlin = new double[nLin]; + double[] ylin = new double[nLin]; + double[] wlin = new double[nLin]; + int counter = 0; + for(int i=0; i<nLen; i++){ + if(zeros[i]){ + xlin[counter] = Math.log(this.xData[0][i]); + ylin[counter] = Math.log(this.yData[i]); + wlin[counter] = Math.abs(this.weight[i]/this.yData[i]); + counter++; + } + } + + Regression reglin = new Regression(xlin, ylin, wlin); + double[] start = new double[nTerms]; + double[] step = new double[nTerms]; + if(this.scaleFlag){ + reglin.linear(); + double[] coeff = reglin.getBestEstimates(); + double[] errrs = reglin.getBestEstimatesErrors(); + + // initial estimates + start[0] = coeff[1]; + start[1] = Math.exp(coeff[0]); + + // initial step sizes + step[0] = errrs[1]/2.0; + step[1] = errrs[0]*start[0]/2.0; + if(step[0]<=0.0 || Fmath.isNaN(step[0]))step[0] = Math.abs(start[0]*0.1); + if(step[1]<=0.0 || Fmath.isNaN(step[1]))step[1] = Math.abs(start[1]*0.1); + } + else{ + reglin.linearGeneral(); + double[] coeff = reglin.getBestEstimates(); + double[] errrs = reglin.getBestEstimatesErrors(); + + // initial estimates + start[0] = coeff[1]; + + // initial step sizes + step[0] = errrs[1]/2.0; + if(step[0]<=0.0 || Fmath.isNaN(step[0]))step[0] = Math.abs(start[0]*0.1); + } + + // Nelder and Mead Simplex Regression + ExponentialSimpleFunction f = new ExponentialSimpleFunction(); + f.scaleOption = this.scaleFlag; + f.scaleFactor = this.yScaleFactor; + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + } + + // FIT TO MULTIPLE EXPOPNENTIALS + + // method for fitting data to mutiple exponentials + // initial estimates calculated internally + public void exponentialMultiple(int nExps){ + this.userSupplied = false; + fitsexponentialMultiple(nExps,0); + } + + // method for fitting data to a multiple exponentials + // initial estimates calculated internally + public void exponentialMultiplePlot(int nExps){ + this.userSupplied = false; + fitsexponentialMultiple(nExps, 1); + } + + // method for fitting data to mutiple exponentials + // user supplied initial estimates + public void exponentialMultiple(int nExps, double[] AandBs){ + this.userSupplied = true; + fitsexponentialMultiple(nExps, 0, AandBs); + } + + // method for fitting data to a multiple exponentials + // user supplied initial estimates + public void exponentialMultiplePlot(int nExps, double[] AandBs){ + this.userSupplied = true; + fitsexponentialMultiple(nExps, 1, AandBs); + } + + // method for fitting data to a multiple exponentials + // initial estimates calculated internally + protected void fitsexponentialMultiple(int nExps, int plotFlag){ + + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=44; + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=2*nExps; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // Estimate of yscale and A - linear transform + int nLen = this.yData.length; + int nLin = nLen; + boolean[] zeros = new boolean[nLen]; + for(int i=0; i<nLen; i++){ + zeros[i] = true; + if(this.xData[0][i]<=0.0D||this.yData[i]<=0.0D){ + zeros[i] = false; + nLin--; + } + } + double[] xlin = new double[nLin]; + double[] ylin = new double[nLin]; + double[] wlin = new double[nLin]; + int counter = 0; + for(int i=0; i<nLen; i++){ + if(zeros[i]){ + xlin[counter] = Math.log(this.xData[0][i]); + ylin[counter] = Math.log(this.yData[i]); + wlin[counter] = Math.abs(this.weight[i]/this.yData[i]); + counter++; + } + } + + Regression reglin = new Regression(xlin, ylin, wlin); + double[] start = new double[nTerms]; + double[] step = new double[nTerms]; + + reglin.linear(); + double[] coeff = reglin.getBestEstimates(); + double[] errrs = reglin.getBestEstimatesErrors(); + + for(int i=0; i<this.nTerms; i+=2){ + // initial estimates + start[i] = Math.exp(coeff[0])/this.nTerms; + start[i+1] = coeff[1]; + + // initial step sizes + step[i] = errrs[0]*start[i]/2.0; + step[i+1] = errrs[1]/2.0; + if(step[i]<=0.0 || Fmath.isNaN(step[i]))step[i] = Math.abs(start[i]*0.1); + if(step[i+1]<=0.0 || Fmath.isNaN(step[i+1]))step[i+1] = Math.abs(start[i+1]*0.1); + } + + // Nelder and Mead Simplex Regression + ExponentialMultipleFunction f = new ExponentialMultipleFunction(); + f.nExps = this.nTerms; + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + } + + // method for fitting data to a multiple exponentials + // user supplied initial estimates calculated + protected void fitsexponentialMultiple(int nExps, int plotFlag, double[] aAndBs){ + + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=44; + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=2*nExps; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + double[] start = new double[nTerms]; + double[] step = new double[nTerms]; + + for(int i=0; i<this.nTerms; i+=2){ + // initial estimates + start[i] = aAndBs[i]; + + // initial step sizes + step[i] = Math.abs(start[i]*0.1); + } + + // Nelder and Mead Simplex Regression + ExponentialMultipleFunction f = new ExponentialMultipleFunction(); + f.nExps = this.nTerms; + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + } + + + + // FIT TO AN EXPOPNENTIAL DISTRIBUTION + + public void exponential(){ + this.fitExponential(0, 0); + } + + public void exponentialPlot(){ + this.fitExponential(1, 0); + } + + public void exponentialOnePar(){ + this.fitExponential(0, 1); + } + + public void exponentialOneParPlot(){ + this.fitExponential(1, 1); + } + + public void exponentialStandard(){ + this.fitExponential(0, 2); + } + + public void exponentialStandardPlot(){ + this.fitExponential(1, 2); + } + + protected void fitExponential(int allTest, int typeFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.userSupplied = false; + switch(typeFlag){ + case 0: this.lastMethod=19; + this.nTerms=3; + break; + case 1: this.lastMethod=20; + this.nTerms=2; + break; + case 2: this.lastMethod=21; + this.nTerms=1; + break; + } + if(!this.scaleFlag)this.nTerms=this.nTerms-1; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + if(this.nTerms==0){ + this.noParameters("Exponential"); + } + else{ + + // Save x-y-w data + double[] xx = new double[this.nData]; + double[] yy = new double[this.nData]; + double[] ww = new double[this.nData]; + + for(int i=0; i<this.nData; i++){ + xx[i]=this.xData[0][i]; + yy[i]=this.yData[i]; + ww[i]=this.weight[i]; + } + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // check y data + Double tempd=null; + ArrayList<Object> retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + double yPeak = tempd.doubleValue(); + Integer tempi = null; + tempi = (Integer)retY.get(5); + int peaki = tempi.intValue(); + + // check sign of y data + String ss = "Exponential"; + boolean ySignFlag = false; + if(yPeak<0.0D){ + this.reverseYsign(ss); + retY = Regression.dataSign(this.yData); + yPeak = -yPeak; + ySignFlag = true; + } + + // check y values for all very small values + boolean magCheck=false; + double magScale = this.checkYallSmall(yPeak, ss); + if(magScale!=1.0D){ + magCheck=true; + yPeak=1.0D; + } + + // minimum value of x + ArrayList<Object> retX = Regression.dataSign(this.xData[0]); + tempd = (Double)retX.get(0); + double xMin = tempd.doubleValue(); + + // estimate of sigma + double yE = yPeak/Math.exp(1.0D); + if(this.yData[0]<yPeak)yE = (yPeak+yData[0])/(2.0D*Math.exp(1.0D)); + double yDiff = Math.abs(yData[0]-yE); + double yTest = 0.0D; + int iE = 0; + for(int i=1; i<this.nData; i++){ + yTest=Math.abs(this.yData[i]-yE); + if(yTest<yDiff){ + yDiff=yTest; + iE=i; + } + } + double sigma = this.xData[0][iE]-this.xData[0][0]; + + // Nelder and Mead Simplex Regression + double[] start = new double[this.nTerms]; + double[] step = new double[this.nTerms]; + + // Fill arrays needed by the Simplex + switch(typeFlag){ + case 0: start[0] = xMin*0.9; //mu + start[1] = sigma; //sigma + if(this.scaleFlag){ + start[2] = yPeak*sigma; //y axis scaling factor + } + step[0] = 0.1D*start[0]; + if(step[0]==0.0D){ + ArrayList<Object> ret0 = Regression.dataSign(xData[0]); + Double tempdd = null; + tempdd = (Double)ret0.get(2); + double xmax = tempdd.doubleValue(); + if(xmax==0.0D){ + tempdd = (Double)ret0.get(0); + xmax = tempdd.doubleValue(); + } + step[0]=xmax*0.1D; + } + step[1] = 0.1D*start[1]; + if(this.scaleFlag)step[2] = 0.1D*start[2]; + break; + case 1: start[0] = sigma; //sigma + if(this.scaleFlag){ + start[1] = yPeak*sigma; //y axis scaling factor + } + step[0] = 0.1D*start[0]; + if(this.scaleFlag)step[1] = 0.1D*start[1]; + break; + case 2: if(this.scaleFlag){ + start[0] = yPeak; //y axis scaling factor + step[0] = 0.1D*start[0]; + } + break; + } + + // Create instance of Exponential function and perform regression + ExponentialFunction ff = new ExponentialFunction(); + ff.typeFlag = typeFlag; + ff.scaleOption = this.scaleFlag; + ff.scaleFactor = this.yScaleFactor; + Object regFun3 = (Object)ff; + this.nelderMead(regFun3, start, step, this.fTol, this.nMax); + + if(allTest==1){ + // Print results + if(!this.supressPrint)this.print(); + // Plot results + int flag = this.plotXY(ff); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // restore data + if(magCheck){ + for(int i =0; i<this.nData; i++){ + this.yData[i] = yy[i]/magScale; + if(this.weightOpt)this.weight[i] = ww[i]/magScale; + } + } + if(ySignFlag){ + for(int i =0; i<this.nData; i++){ + this.yData[i]=-this.yData[i]; + } + } + } + } + + // check for zero and negative values + public void checkZeroNeg(double [] xx, double[] yy, double[] ww){ + int jj = 0; + boolean test = true; + for(int i=0; i<this.nData; i++){ + if(yy[i]<=0.0D){ + if(i<=jj){ + test=true; + jj = i; + while(test){ + jj++; + if(jj>=this.nData)throw new ArithmeticException("all zero cumulative data!!"); + if(yy[jj]>0.0D){ + yy[i]=yy[jj]; + xx[i]=xx[jj]; + ww[i]=ww[jj]; + test=false; + } + } + } + else{ + if(i==this.nData-1){ + yy[i]=yy[i-1]; + xx[i]=xx[i-1]; + ww[i]=ww[i-1]; + } + else{ + yy[i]=(yy[i-1] + yy[i+1])/2.0D; + xx[i]=(xx[i-1] + xx[i+1])/2.0D; + ww[i]=(ww[i-1] + ww[i+1])/2.0D; + } + } + } + } + } + + public void rayleigh(){ + this.fitRayleigh(0, 0); + } + + public void rayleighPlot(){ + this.fitRayleigh(1, 0); + } + + protected void fitRayleigh(int allTest, int typeFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=22; + this.userSupplied = false; + this.nTerms=2; + if(!this.scaleFlag)this.nTerms=this.nTerms-1; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // check y data + Double tempd=null; + ArrayList<Object> retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + double yPeak = tempd.doubleValue(); + Integer tempi = null; + tempi = (Integer)retY.get(5); + int peaki = tempi.intValue(); + + // check sign of y data + String ss = "Rayleigh"; + boolean ySignFlag = false; + if(yPeak<0.0D){ + this.reverseYsign(ss); + retY = Regression.dataSign(this.yData); + yPeak = -yPeak; + ySignFlag = true; + } + + // check y values for all very small values + boolean magCheck=false; + double magScale = this.checkYallSmall(yPeak, ss); + if(magScale!=1.0D){ + magCheck=true; + yPeak=1.0D; + } + + // Save x-y-w data + double[] xx = new double[this.nData]; + double[] yy = new double[this.nData]; + double[] ww = new double[this.nData]; + + for(int i=0; i<this.nData; i++){ + xx[i]=this.xData[0][i]; + yy[i]=this.yData[i]; + ww[i]=this.weight[i]; + } + + // minimum value of x + ArrayList<Object> retX = Regression.dataSign(this.xData[0]); + tempd = (Double)retX.get(0); + double xMin = tempd.doubleValue(); + + // maximum value of x + tempd = (Double)retX.get(2); + double xMax = tempd.doubleValue(); + + // Calculate x value at peak y (estimate of the 'distribution mode') + double distribMode = xData[0][peaki]; + + // Calculate an estimate of the half-height width + double sd = Math.log(2.0D)*halfWidth(xData[0], yData); + + // Calculate the cumulative probability and return ordinate scaling factor estimate + double[] cumX = new double[this.nData]; + double[] cumY = new double[this.nData]; + double[] cumW = new double[this.nData]; + ErrorProp[] cumYe = ErrorProp.oneDarray(this.nData); + double yScale = this.calculateCumulativeValues(cumX, cumY, cumW, cumYe, peaki, yPeak, distribMode, ss); + + //Calculate log transform + for(int i=0; i<this.nData; i++){ + cumYe[i] = ErrorProp.minus(1.0D,cumYe[i]); + cumYe[i] = ErrorProp.over(1.0D, cumYe[i]); + cumYe[i] = ErrorProp.log(cumYe[i]); + cumY[i] = cumYe[i].getValue(); + cumW[i] = cumYe[i].getError(); + } + + // Fill data arrays with transformed data + for(int i =0; i<this.nData; i++){ + xData[0][i] = cumX[i]; + yData[i] = cumY[i]; + weight[i] = cumW[i]; + } + boolean weightOptHold = this.weightOpt; + this.weightOpt=true; + + // Nelder and Mead Simplex Regression for semi-linearised Rayleigh + // disable statistical analysis + this.statFlag=false; + + // Fill arrays needed by the Simplex + double[] start = new double[this.nTerms]; + double[] step = new double[this.nTerms]; + for(int i=0; i<this.nTerms; i++){ + start[i]=1.0D; + step[i]=0.2D; + } + start[0] = sd; //sigma + step[0] = 0.2D; + this.addConstraint(0,-1,0.0D); + + // Create instance of log function and perform regression + RayleighFunctionTwo f = new RayleighFunctionTwo(); + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + // Get best estimates of log regression + double[] ests = this.best.clone(); + + // enable statistical analysis + this.statFlag=true; + + // restore data reversing the loglog transform but maintaining any sign reversals + this.weightOpt=weightOptHold; + for(int i =0; i<this.nData; i++){ + xData[0][i] = xx[i]; + yData[i] = yy[i]; + weight[i] = ww[i]; + } + + // Fill arrays needed by the Simplex + start[0] = ests[0]; //sigma + if(this.scaleFlag){ + start[1] = 1.0/yScale; //y axis scaling factor + } + step[0] = 0.1D*start[0]; + if(this.scaleFlag)step[1] = 0.1D*start[1]; + + + // Create instance of Rayleigh function and perform regression + RayleighFunctionOne ff = new RayleighFunctionOne(); + ff.scaleOption = this.scaleFlag; + ff.scaleFactor = this.yScaleFactor; + Object regFun3 = (Object)ff; + this.nelderMead(regFun3, start, step, this.fTol, this.nMax); + + if(allTest==1){ + // Print results + if(!this.supressPrint)this.print(); + // Plot results + int flag = this.plotXY(ff); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // restore data + if(magCheck){ + for(int i =0; i<this.nData; i++){ + this.yData[i] = yy[i]/magScale; + if(this.weightOpt)this.weight[i] = ww[i]/magScale; + } + } + if(ySignFlag){ + for(int i =0; i<this.nData; i++){ + this.yData[i]=-this.yData[i]; + } + } + } + + // Shifted Pareto + public void paretoShifted(){ + this.fitPareto(0, 3); + } + + public void paretoThreePar(){ + this.fitPareto(0, 3); + } + + public void paretoShiftedPlot(){ + this.fitPareto(1, 3); + } + public void paretoThreeParPlot(){ + this.fitPareto(1, 3); + } + + // Two Parameter Pareto + public void paretoTwoPar(){ + this.fitPareto(0, 2); + } + // Deprecated + public void pareto(){ + this.fitPareto(0, 2); + } + + public void paretoTwoParPlot(){ + this.fitPareto(1, 2); + } + // Deprecated + public void paretoPlot(){ + this.fitPareto(1, 2); + } + + // One Parameter Pareto + public void paretoOnePar(){ + this.fitPareto(0, 1); + } + + public void paretoOneParPlot(){ + this.fitPareto(1, 1); + } + + // method for fitting data to a Pareto distribution + protected void fitPareto(int allTest, int typeFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.userSupplied = false; + switch(typeFlag){ + case 3: this.lastMethod=29; + this.nTerms=4; + break; + case 2: this.lastMethod=23; + this.nTerms=3; + break; + case 1: this.lastMethod=24; + this.nTerms=2; + break; + } + + if(!this.scaleFlag)this.nTerms=this.nTerms-1; + this.linNonLin = false; + this.zeroCheck = false; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + String ss = "Pareto"; + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // check y data + Double tempd=null; + ArrayList<Object> retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + double yPeak = tempd.doubleValue(); + Integer tempi = null; + tempi = (Integer)retY.get(5); + int peaki = tempi.intValue(); + + // check for infinity + if(this.infinityCheck(yPeak, peaki)){ + retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + yPeak = tempd.doubleValue(); + tempi = null; + tempi = (Integer)retY.get(5); + peaki = tempi.intValue(); + } + + // check sign of y data + boolean ySignFlag = false; + if(yPeak<0.0D){ + this.reverseYsign(ss); + retY = Regression.dataSign(this.yData); + yPeak = -yPeak; + ySignFlag = true; + } + + // check y values for all very small values + boolean magCheck=false; + double magScale = this.checkYallSmall(yPeak, ss); + if(magScale!=1.0D){ + magCheck=true; + yPeak=1.0D; + } + + // minimum value of x + ArrayList<Object> retX = Regression.dataSign(this.xData[0]); + tempd = (Double)retX.get(0); + double xMin = tempd.doubleValue(); + + // maximum value of x + tempd = (Double)retX.get(2); + double xMax = tempd.doubleValue(); + + // Calculate x value at peak y (estimate of the 'distribution mode') + double distribMode = xData[0][peaki]; + + // Calculate an estimate of the half-height width + double sd = Math.log(2.0D)*halfWidth(xData[0], yData); + + // Save x-y-w data + double[] xx = new double[this.nData]; + double[] yy = new double[this.nData]; + double[] ww = new double[this.nData]; + + for(int i=0; i<this.nData; i++){ + xx[i]=this.xData[0][i]; + yy[i]=this.yData[i]; + ww[i]=this.weight[i]; + } + + // Calculate the cumulative probability and return ordinate scaling factor estimate + double[] cumX = new double[this.nData]; + double[] cumY = new double[this.nData]; + double[] cumW = new double[this.nData]; + ErrorProp[] cumYe = ErrorProp.oneDarray(this.nData); + double yScale = this.calculateCumulativeValues(cumX, cumY, cumW, cumYe, peaki, yPeak, distribMode, ss); + + //Calculate l - cumlative probability + for(int i=0; i<this.nData; i++){ + cumYe[i] = ErrorProp.minus(1.0D,cumYe[i]); + cumY[i] = cumYe[i].getValue(); + cumW[i] = cumYe[i].getError(); + } + + // Fill data arrays with transformed data + for(int i =0; i<this.nData; i++){ + xData[0][i] = cumX[i]; + yData[i] = cumY[i]; + weight[i] = cumW[i]; + } + boolean weightOptHold = this.weightOpt; + this.weightOpt=true; + + // Nelder and Mead Simplex Regression for Pareto estimated cdf + // disable statistical analysis + this.statFlag=false; + + // Fill arrays needed by the Simplex + double[] start = new double[this.nTerms]; + double[] step = new double[this.nTerms]; + for(int i=0; i<this.nTerms; i++){ + start[i]=1.0D; + step[i]=0.2D; + } + switch(typeFlag){ + case 3: start[0] = 2; //alpha + start[1] = xMin*0.9D; //beta + if(xMin<0){ //theta + start[2] = -xMin*1.1D; + } + else{ + start[2] = xMin*0.01; + } + if(start[1]<0.0D)start[1]=0.0D; + step[0] = 0.2D*start[0]; + step[1] = 0.2D*start[1]; + if(step[1]==0.0D){ + double xmax = xMax; + if(xmax==0.0D){ + xmax = xMin; + } + step[1]=xmax*0.1D; + } + this.addConstraint(0,-1,0.0D); + this.addConstraint(1,-1,0.0D); + this.addConstraint(1,+1,xMin); + break; + case 2: if(xMin<0)System.out.println("Method: FitParetoTwoPar/FitParetoTwoParPlot\nNegative data values present\nFitParetoShifted/FitParetoShiftedPlot would have been more appropriate"); + start[0] = 2; //alpha + start[1] = xMin*0.9D; //beta + if(start[1]<0.0D)start[1]=0.0D; + step[0] = 0.2D*start[0]; + step[1] = 0.2D*start[1]; + if(step[1]==0.0D){ + double xmax = xMax; + if(xmax==0.0D){ + xmax = xMin; + } + step[1]=xmax*0.1D; + } + this.addConstraint(0,-1,0.0D); + this.addConstraint(1,-1,0.0D); + break; + case 1: if(xMin<0)System.out.println("Method: FitParetoOnePar/FitParetoOneParPlot\nNegative data values present\nFitParetoShifted/FitParetoShiftedPlot would have been more appropriate"); + start[0] = 2; //alpha + step[0] = 0.2D*start[0]; + this.addConstraint(0,-1,0.0D); + this.addConstraint(1,-1,0.0D); + break; + } + + // Create instance of cdf function and perform regression + ParetoFunctionTwo f = new ParetoFunctionTwo(); + f.typeFlag = typeFlag; + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + // Get best estimates of cdf regression + double[] ests = this.best.clone(); + + // Nelder and Mead Simplex Regression for Pareto + // using best estimates from cdf regression as initial estimates + + // enable statistical analysis + this.statFlag=true; + + // restore data reversing the cdf transform but maintaining any sign reversals + this.weightOpt=weightOptHold; + for(int i =0; i<this.nData; i++){ + xData[0][i] = xx[i]; + yData[i] = yy[i]; + weight[i] = ww[i]; + } + + // Fill arrays needed by the Simplex + switch(typeFlag){ + case 3: start[0] = ests[0]; //alpha + if(start[0]<=0.0D){ + if(start[0]==0.0D){ + start[0]=1.0D; + } + else{ + start[0] = Math.min(1.0D,-start[0]); + } + } + start[1] = ests[1]; //beta + if(start[1]<=0.0D){ + if(start[1]==0.0D){ + start[1]=1.0D; + } + else{ + start[1] = Math.min(1.0D,-start[1]); + } + } + start[2] = ests[2]; + if(this.scaleFlag){ + start[3] = 1.0/yScale; //y axis scaling factor + } + step[0] = 0.1D*start[0]; + step[1] = 0.1D*start[1]; + if(step[1]==0.0D){ + double xmax = xMax; + if(xmax==0.0D){ + xmax = xMin; + } + step[1]=xmax*0.1D; + } + if(this.scaleFlag)step[2] = 0.1D*start[2]; + break; + case 2: start[0] = ests[0]; //alpha + if(start[0]<=0.0D){ + if(start[0]==0.0D){ + start[0]=1.0D; + } + else{ + start[0] = Math.min(1.0D,-start[0]); + } + } + start[1] = ests[1]; //beta + if(start[1]<=0.0D){ + if(start[1]==0.0D){ + start[1]=1.0D; + } + else{ + start[1] = Math.min(1.0D,-start[1]); + } + } + if(this.scaleFlag){ + start[2] = 1.0/yScale; //y axis scaling factor + } + step[0] = 0.1D*start[0]; + step[1] = 0.1D*start[1]; + if(step[1]==0.0D){ + double xmax = xMax; + if(xmax==0.0D){ + xmax = xMin; + } + step[1]=xmax*0.1D; + } + if(this.scaleFlag)step[2] = 0.1D*start[2]; + break; + case 1: start[0] = ests[0]; //alpha + if(start[0]<=0.0D){ + if(start[0]==0.0D){ + start[0]=1.0D; + } + else{ + start[0] = Math.min(1.0D,-start[0]); + } + } + if(this.scaleFlag){ + start[1] = 1.0/yScale; //y axis scaling factor + } + step[0] = 0.1D*start[0]; + if(this.scaleFlag)step[1] = 0.1D*start[1]; + break; + } + + // Create instance of Pareto function and perform regression + ParetoFunctionOne ff = new ParetoFunctionOne(); + ff.typeFlag = typeFlag; + ff.scaleOption = this.scaleFlag; + ff.scaleFactor = this.yScaleFactor; + Object regFun3 = (Object)ff; + this.nelderMead(regFun3, start, step, this.fTol, this.nMax); + + if(allTest==1){ + // Print results + if(!this.supressPrint)this.print(); + // Plot results + int flag = this.plotXY(ff); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + // restore data + this.weightOpt = weightOptHold; + if(magCheck){ + for(int i =0; i<this.nData; i++){ + this.yData[i] = yy[i]/magScale; + if(this.weightOpt)this.weight[i] = ww[i]/magScale; + } + } + if(ySignFlag){ + for(int i =0; i<this.nData; i++){ + this.yData[i]=-this.yData[i]; + } + } + } + + + // method for fitting data to a sigmoid threshold function + public void sigmoidThreshold(){ + fitSigmoidThreshold(0); + } + + // method for fitting data to a sigmoid threshold function with plot and print out + public void sigmoidThresholdPlot(){ + fitSigmoidThreshold(1); + } + + + // method for fitting data to a sigmoid threshold function + protected void fitSigmoidThreshold(int plotFlag){ + + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=25; + this.userSupplied = false; + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=3; + if(!this.scaleFlag)this.nTerms=2; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // Estimate of theta + double yymin = Fmath.minimum(this.yData); + double yymax = Fmath.maximum(this.yData); + int dirFlag = 1; + if(yymin<0)dirFlag=-1; + double yyymid = (yymax - yymin)/2.0D; + double yyxmidl = xData[0][0]; + int ii = 1; + int nLen = this.yData.length; + boolean test = true; + while(test){ + if(this.yData[ii]>=dirFlag*yyymid){ + yyxmidl = xData[0][ii]; + test = false; + } + else{ + ii++; + if(ii>=nLen){ + yyxmidl = Stat.mean(this.xData[0]); + ii=nLen-1; + test = false; + } + } + } + double yyxmidh = xData[0][nLen-1]; + int jj = nLen-1; + test = true; + while(test){ + if(this.yData[jj]<=dirFlag*yyymid){ + yyxmidh = xData[0][jj]; + test = false; + } + else{ + jj--; + if(jj<0){ + yyxmidh = Stat.mean(this.xData[0]); + jj=1; + test = false; + } + } + } + int thetaPos = (ii+jj)/2; + double theta0 = xData[0][thetaPos]; + + // estimate of slope + double thetaSlope1 = 2.0D*(yData[nLen-1] - theta0)/(xData[0][nLen-1] - xData[0][thetaPos]); + double thetaSlope2 = 2.0D*theta0/(xData[0][thetaPos] - xData[0][nLen-1]); + double thetaSlope = Math.max(thetaSlope1, thetaSlope2); + + // initial estimates + double[] start = new double[nTerms]; + start[0] = 4.0D*thetaSlope; + if(dirFlag==1){ + start[0] /= yymax; + } + else{ + start[0] /= yymin; + } + start[1] = theta0; + if(this.scaleFlag){ + if(dirFlag==1){ + start[2] = yymax; + } + else{ + start[2] = yymin; + } + } + + // initial step sizes + double[] step = new double[nTerms]; + for(int i=0; i<nTerms; i++)step[i] = 0.1*start[i]; + if(step[0]==0.0D)step[0] = 0.1*(xData[0][nLen-1] - xData[0][0])/(yData[nLen-1] - yData[0]); + if(step[1]==0.0D)step[1] = (xData[0][nLen-1] - xData[0][0])/20.0D; + if(this.scaleFlag)if(step[2]==0.0D)step[2] = 0.1*(yData[nLen-1] - yData[0]); + + // Nelder and Mead Simplex Regression + SigmoidThresholdFunction f = new SigmoidThresholdFunction(); + f.scaleOption = this.scaleFlag; + f.scaleFactor = this.yScaleFactor; + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + } + // method for fitting data to a Hill/Sips Sigmoid + public void sigmoidHillSips(){ + fitsigmoidHillSips(0); + } + + // method for fitting data to a Hill/Sips Sigmoid with plot and print out + public void sigmoidHillSipsPlot(){ + fitsigmoidHillSips(1); + } + + // method for fitting data to a Hill/Sips Sigmoid + protected void fitsigmoidHillSips(int plotFlag){ + + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=28; + this.userSupplied = false; + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=3; + if(!this.scaleFlag)this.nTerms=2; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // Estimate of theta + double yymin = Fmath.minimum(this.yData); + double yymax = Fmath.maximum(this.yData); + int dirFlag = 1; + if(yymin<0)dirFlag=-1; + double yyymid = (yymax - yymin)/2.0D; + double yyxmidl = xData[0][0]; + int ii = 1; + int nLen = this.yData.length; + boolean test = true; + while(test){ + if(this.yData[ii]>=dirFlag*yyymid){ + yyxmidl = xData[0][ii]; + test = false; + } + else{ + ii++; + if(ii>=nLen){ + yyxmidl = Stat.mean(this.xData[0]); + ii=nLen-1; + test = false; + } + } + } + double yyxmidh = xData[0][nLen-1]; + int jj = nLen-1; + test = true; + while(test){ + if(this.yData[jj]<=dirFlag*yyymid){ + yyxmidh = xData[0][jj]; + test = false; + } + else{ + jj--; + if(jj<0){ + yyxmidh = Stat.mean(this.xData[0]); + jj=1; + test = false; + } + } + } + int thetaPos = (ii+jj)/2; + double theta0 = xData[0][thetaPos]; + + // initial estimates + double[] start = new double[nTerms]; + start[0] = theta0; + start[1] = 1; + if(this.scaleFlag){ + if(dirFlag==1){ + start[2] = yymax; + } + else{ + start[2] = yymin; + } + } + + // initial step sizes + double[] step = new double[nTerms]; + for(int i=0; i<nTerms; i++)step[i] = 0.1*start[i]; + if(step[0]==0.0D)step[0] = (xData[0][nLen-1] - xData[0][0])/20.0D; + if(this.scaleFlag)if(step[2]==0.0D)step[2] = 0.1*(yData[nLen-1] - yData[0]); + + // Nelder and Mead Simplex Regression + SigmoidHillSipsFunction f = new SigmoidHillSipsFunction(); + f.scaleOption = this.scaleFlag; + f.scaleFactor = this.yScaleFactor; + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + } + + // method for fitting data to a EC50 dose response curve + public void ec50(){ + fitEC50(0); + } + + // method for fitting data to a EC50 dose response curve with plot and print out + public void ec50Plot(){ + fitEC50(1); + } + + // method for fitting data to a EC50 dose response curve + // bottom constrained to zero or positive values + public void ec50constrained(){ + fitEC50(2); + } + + // method for fitting data to a EC50 dose response curve with plot and print out + // bottom constrained to zero or positive values + public void ec50constrainedPlot(){ + fitEC50(3); + } + + // method for fitting data to a logEC50 dose response curve + protected void fitEC50(int cpFlag){ + + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + int plotFlag = 0; + boolean constrained = false; + this.userSupplied = false; + switch(cpFlag){ + case 0: this.lastMethod= 39; + plotFlag = 0; + break; + case 1: this.lastMethod= 39; + plotFlag = 1; + break; + case 2: this.lastMethod= 41; + plotFlag = 0; + constrained = true; + break; + case 3: this.lastMethod= 41; + plotFlag = 1; + constrained = true; + break; + } + + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=4; + this.scaleFlag = false; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // Estimate of bottom and top + double bottom = Fmath.minimum(this.yData); + double top = Fmath.maximum(this.yData); + + // Estimate of EC50 + int dirFlag = 1; + double yyymid = (top - bottom)/2.0D; + double yyxmidl = xData[0][0]; + int ii = 1; + int nLen = this.yData.length; + boolean test = true; + while(test){ + if(this.yData[ii]>=dirFlag*yyymid){ + yyxmidl = xData[0][ii]; + test = false; + } + else{ + ii++; + if(ii>=nLen){ + yyxmidl = Stat.mean(this.xData[0]); + ii=nLen-1; + test = false; + } + } + } + double yyxmidh = xData[0][nLen-1]; + int jj = nLen-1; + test = true; + while(test){ + if(this.yData[jj]<=dirFlag*yyymid){ + yyxmidh = xData[0][jj]; + test = false; + } + else{ + jj--; + if(jj<0){ + yyxmidh = Stat.mean(this.xData[0]); + jj=1; + test = false; + } + } + } + int thetaPos = (ii+jj)/2; + double EC50 = xData[0][thetaPos]; + + // estimate of slope + double thetaSlope1 = 2.0D*(yData[nLen-1] - EC50)/(xData[0][nLen-1] - xData[0][thetaPos]); + double thetaSlope2 = 2.0D*EC50/(xData[0][thetaPos] - xData[0][nLen-1]); + double hillSlope = Math.max(thetaSlope1, thetaSlope2); + + // initial estimates + double[] start = new double[nTerms]; + start[0] = bottom; + start[1] = top; + start[2] = EC50; + start[3] = -hillSlope; + + // initial step sizes + double[] step = new double[nTerms]; + for(int i=0; i<nTerms; i++)step[i] = 0.1*start[i]; + if(step[0]==0.0D)step[0] = 0.1*(yData[nLen-1] - yData[0]); + if(step[1]==0.0D)step[1] = 0.1*(yData[nLen-1] - yData[0]) + yData[nLen-1]; + if(step[2]==0.0D)step[2] = 0.05*(xData[0][nLen-1] - xData[0][0]); + if(step[3]==0.0D)step[3] = 0.1*(xData[0][nLen-1] - xData[0][0])/(yData[nLen-1] - yData[0]); + + // Constrained option + if(constrained)this.addConstraint(0, -1, 0.0D); + + // Nelder and Mead Simplex Regression + EC50Function f = new EC50Function(); + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + } + + // method for fitting data to a logEC50 dose response curve + public void logEC50(){ + fitLogEC50(0); + } + + // method for fitting data to a logEC50 dose response curve with plot and print out + public void logEC50Plot(){ + fitLogEC50(1); + } + + // method for fitting data to a logEC50 dose response curve + // bottom constrained to zero or positive values + public void logEC50constrained(){ + fitLogEC50(2); + } + + // method for fitting data to a logEC50 dose response curve with plot and print out + // bottom constrained to zero or positive values + public void logEC50constrainedPlot(){ + fitLogEC50(3); + } + + // method for fitting data to a logEC50 dose response curve + protected void fitLogEC50(int cpFlag){ + + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + int plotFlag = 0; + boolean constrained = false; + this.userSupplied = false; + switch(cpFlag){ + case 0: this.lastMethod= 40; + plotFlag = 0; + break; + case 1: this.lastMethod= 40; + plotFlag = 1; + break; + case 2: this.lastMethod= 42; + plotFlag = 0; + constrained = true; + break; + case 3: this.lastMethod= 42; + plotFlag = 1; + constrained = true; + break; + } + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=4; + this.scaleFlag = false; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // Estimate of bottom and top + double bottom = Fmath.minimum(this.yData); + double top = Fmath.maximum(this.yData); + + // Estimate of LogEC50 + int dirFlag = 1; + double yyymid = (top - bottom)/2.0D; + double yyxmidl = xData[0][0]; + int ii = 1; + int nLen = this.yData.length; + boolean test = true; + while(test){ + if(this.yData[ii]>=dirFlag*yyymid){ + yyxmidl = xData[0][ii]; + test = false; + } + else{ + ii++; + if(ii>=nLen){ + yyxmidl = Stat.mean(this.xData[0]); + ii=nLen-1; + test = false; + } + } + } + double yyxmidh = xData[0][nLen-1]; + int jj = nLen-1; + test = true; + while(test){ + if(this.yData[jj]<=dirFlag*yyymid){ + yyxmidh = xData[0][jj]; + test = false; + } + else{ + jj--; + if(jj<0){ + yyxmidh = Stat.mean(this.xData[0]); + jj=1; + test = false; + } + } + } + int thetaPos = (ii+jj)/2; + double logEC50 = xData[0][thetaPos]; + + // estimate of slope + double thetaSlope1 = 2.0D*(yData[nLen-1] - logEC50)/(xData[0][nLen-1] - xData[0][thetaPos]); + double thetaSlope2 = 2.0D*logEC50/(xData[0][thetaPos] - xData[0][nLen-1]); + double hillSlope = Math.max(thetaSlope1, thetaSlope2); + + // initial estimates + double[] start = new double[nTerms]; + start[0] = bottom; + start[1] = top; + start[2] = logEC50; + start[3] = hillSlope; + + // initial step sizes + double[] step = new double[nTerms]; + for(int i=0; i<nTerms; i++)step[i] = 0.1*start[i]; + if(step[0]==0.0D)step[0] = 0.1*(yData[nLen-1] - yData[0]); + if(step[1]==0.0D)step[1] = 0.1*(yData[nLen-1] - yData[0]) + yData[nLen-1]; + if(step[2]==0.0D)step[2] = 0.05*(xData[0][nLen-1] - xData[0][0]); + if(step[3]==0.0D)step[3] = 0.1*(xData[0][nLen-1] - xData[0][0])/(yData[nLen-1] - yData[0]); + + // Constrained option + if(constrained)this.addConstraint(0, -1, 0.0D); + + // Nelder and Mead Simplex Regression + LogEC50Function f = new LogEC50Function(); + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + } + + // method for fitting data to a rectangular hyberbola + public void rectangularHyperbola(){ + fitRectangularHyperbola(0); + } + + // method for fitting data to a rectangular hyberbola with plot and print out + public void rectangularHyperbolaPlot(){ + fitRectangularHyperbola(1); + } + + // method for fitting data to a rectangular hyperbola + protected void fitRectangularHyperbola(int plotFlag){ + + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=26; + this.userSupplied = false; + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=2; + if(!this.scaleFlag)this.nTerms=1; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // Estimate of theta + double yymin = Fmath.minimum(this.yData); + double yymax = Fmath.maximum(this.yData); + int dirFlag = 1; + if(yymin<0)dirFlag=-1; + double yyymid = (yymax - yymin)/2.0D; + double yyxmidl = xData[0][0]; + int ii = 1; + int nLen = this.yData.length; + boolean test = true; + while(test){ + if(this.yData[ii]>=dirFlag*yyymid){ + yyxmidl = xData[0][ii]; + test = false; + } + else{ + ii++; + if(ii>=nLen){ + yyxmidl = Stat.mean(this.xData[0]); + ii=nLen-1; + test = false; + } + } + } + double yyxmidh = xData[0][nLen-1]; + int jj = nLen-1; + test = true; + while(test){ + if(this.yData[jj]<=dirFlag*yyymid){ + yyxmidh = xData[0][jj]; + test = false; + } + else{ + jj--; + if(jj<0){ + yyxmidh = Stat.mean(this.xData[0]); + jj=1; + test = false; + } + } + } + int thetaPos = (ii+jj)/2; + double theta0 = xData[0][thetaPos]; + + // initial estimates + double[] start = new double[nTerms]; + start[0] = theta0; + if(this.scaleFlag){ + if(dirFlag==1){ + start[1] = yymax; + } + else{ + start[1] = yymin; + } + } + + // initial step sizes + double[] step = new double[nTerms]; + for(int i=0; i<nTerms; i++)step[i] = 0.1*start[i]; + if(step[0]==0.0D)step[0] = (xData[0][nLen-1] - xData[0][0])/20.0D; + if(this.scaleFlag)if(step[1]==0.0D)step[1] = 0.1*(yData[nLen-1] - yData[0]); + + // Nelder and Mead Simplex Regression + RectangularHyperbolaFunction f = new RectangularHyperbolaFunction(); + f.scaleOption = this.scaleFlag; + f.scaleFactor = this.yScaleFactor; + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + } + +// method for fitting data to a scaled Heaviside Step Function + public void stepFunction(){ + fitStepFunction(0); + } + + // method for fitting data to a scaled Heaviside Step Function with plot and print out + public void stepFunctionPlot(){ + fitStepFunction(1); + } + + // method for fitting data to a scaled Heaviside Step Function + protected void fitStepFunction(int plotFlag){ + + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=27; + this.userSupplied = false; + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=2; + if(!this.scaleFlag)this.nTerms=1; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // Estimate of theta + double yymin = Fmath.minimum(this.yData); + double yymax = Fmath.maximum(this.yData); + int dirFlag = 1; + if(yymin<0)dirFlag=-1; + double yyymid = (yymax - yymin)/2.0D; + double yyxmidl = xData[0][0]; + int ii = 1; + int nLen = this.yData.length; + boolean test = true; + while(test){ + if(this.yData[ii]>=dirFlag*yyymid){ + yyxmidl = xData[0][ii]; + test = false; + } + else{ + ii++; + if(ii>=nLen){ + yyxmidl = Stat.mean(this.xData[0]); + ii=nLen-1; + test = false; + } + } + } + double yyxmidh = xData[0][nLen-1]; + int jj = nLen-1; + test = true; + while(test){ + if(this.yData[jj]<=dirFlag*yyymid){ + yyxmidh = xData[0][jj]; + test = false; + } + else{ + jj--; + if(jj<0){ + yyxmidh = Stat.mean(this.xData[0]); + jj=1; + test = false; + } + } + } + int thetaPos = (ii+jj)/2; + double theta0 = xData[0][thetaPos]; + + // initial estimates + double[] start = new double[nTerms]; + start[0] = theta0; + if(this.scaleFlag){ + if(dirFlag==1){ + start[1] = yymax; + } + else{ + start[1] = yymin; + } + } + + // initial step sizes + double[] step = new double[nTerms]; + for(int i=0; i<nTerms; i++)step[i] = 0.1*start[i]; + if(step[0]==0.0D)step[0] = (xData[0][nLen-1] - xData[0][0])/20.0D; + if(this.scaleFlag)if(step[1]==0.0D)step[1] = 0.1*(yData[nLen-1] - yData[0]); + + // Nelder and Mead Simplex Regression + StepFunctionFunction f = new StepFunctionFunction(); + f.scaleOption = this.scaleFlag; + f.scaleFactor = this.yScaleFactor; + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + } + + // Fit to a Logistic + public void logistic(){ + this.fitLogistic(0); + } + + // Fit to a Logistic + public void logisticPlot(){ + + this.fitLogistic(1); + } + + // Fit data to a Logistic probability function + protected void fitLogistic(int plotFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=30; + this.userSupplied = false; + this.linNonLin = false; + this.zeroCheck = false; + this.nTerms=3; + if(!this.scaleFlag)this.nTerms=2; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // check sign of y data + Double tempd=null; + ArrayList<Object> retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + double yPeak = tempd.doubleValue(); + boolean yFlag = false; + if(yPeak<0.0D){ + System.out.println("Regression.fitLogistic(): This implementation of the Logistic distribution takes only positive y values\n(noise taking low values below zero are allowed)"); + System.out.println("All y values have been multiplied by -1 before fitting"); + for(int i =0; i<this.nData; i++){ + yData[i] = -yData[i]; + } + retY = Regression.dataSign(yData); + yFlag=true; + } + + // Calculate x value at peak y (estimate of the Logistic mean) + ArrayList<Object> ret1 = Regression.dataSign(yData); + Integer tempi = null; + tempi = (Integer)ret1.get(5); + int peaki = tempi.intValue(); + double mu = xData[0][peaki]; + + // Calculate an estimate of the beta + double beta = Math.sqrt(6.0D)*halfWidth(xData[0], yData)/Math.PI; + + // Calculate estimate of y scale + tempd = (Double)ret1.get(4); + double ym = tempd.doubleValue(); + ym=ym*beta*Math.sqrt(2.0D*Math.PI); + + // Fill arrays needed by the Simplex + double[] start = new double[this.nTerms]; + double[] step = new double[this.nTerms]; + start[0] = mu; + start[1] = beta; + if(this.scaleFlag){ + start[2] = ym; + } + step[0] = 0.1D*beta; + step[1] = 0.1D*start[1]; + if(step[1]==0.0D){ + ArrayList<Object> ret0 = Regression.dataSign(xData[0]); + Double tempdd = null; + tempdd = (Double)ret0.get(2); + double xmax = tempdd.doubleValue(); + if(xmax==0.0D){ + tempdd = (Double)ret0.get(0); + xmax = tempdd.doubleValue(); + } + step[0]=xmax*0.1D; + } + if(this.scaleFlag)step[2] = 0.1D*start[2]; + + // Nelder and Mead Simplex Regression + LogisticFunction f = new LogisticFunction(); + this.addConstraint(1,-1,0.0D); + f.scaleOption = this.scaleFlag; + f.scaleFactor = this.yScaleFactor; + Object regFun2 = (Object)f; + this.nelderMead(regFun2, start, step, this.fTol, this.nMax); + + if(plotFlag==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(f); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + if(yFlag){ + // restore data + for(int i=0; i<this.nData-1; i++){ + this.yData[i]=-this.yData[i]; + } + } + + } + + public void beta(){ + this.fitBeta(0, 0); + } + + public void betaPlot(){ + this.fitBeta(1, 0); + } + + public void betaMinMax(){ + this.fitBeta(0, 1); + } + + public void betaMinMaxPlot(){ + this.fitBeta(1, 1); + } + + protected void fitBeta(int allTest, int typeFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.userSupplied = false; + switch(typeFlag){ + case 0: this.lastMethod=31; + this.nTerms=3; + break; + case 1: this.lastMethod=32; + this.nTerms=5; + break; + } + if(!this.scaleFlag)this.nTerms=this.nTerms-1; + + this.zeroCheck = false; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // check sign of y data + Double tempd=null; + ArrayList<Object> retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + double yPeak = tempd.doubleValue(); + boolean yFlag = false; + if(yPeak<0.0D){ + System.out.println("Regression.fitBeta(): This implementation of the Beta distribution takes only positive y values\n(noise taking low values below zero are allowed)"); + System.out.println("All y values have been multiplied by -1 before fitting"); + for(int i =0; i<this.nData; i++){ + yData[i] = -yData[i]; + } + retY = Regression.dataSign(yData); + yFlag=true; + } + + // check x data + ArrayList<Object> retX = Regression.dataSign(xData[0]); + Integer tempi = null; + + // Calculate x value at peak y (estimate of the 'distribution mode') + tempi = (Integer)retY.get(5); + int peaki = tempi.intValue(); + double distribMode = xData[0][peaki]; + + // minimum value + tempd = (Double)retX.get(0); + double minX = tempd.doubleValue(); + // maximum value + tempd = (Double)retX.get(2); + double maxX = tempd.doubleValue(); + // mean value + tempd = (Double)retX.get(8); + double meanX = tempd.doubleValue(); + + + // test that data is within range + if(typeFlag==0){ + if(minX<0.0D){ + System.out.println("Regression: beta: data points must be greater than or equal to 0"); + System.out.println("method betaMinMax used in place of method beta"); + typeFlag = 1; + this.lastMethod=32; + this.nTerms=5; + } + if(maxX>1.0D){ + System.out.println("Regression: beta: data points must be less than or equal to 1"); + System.out.println("method betaMinMax used in place of method beta"); + typeFlag = 1; + this.lastMethod=32; + this.nTerms=5; + } + } + + // Calculate an estimate of the alpha, beta and scale factor + double dMode = distribMode; + double dMean = meanX; + if(typeFlag==1){ + dMode = (distribMode - minX*0.9D)/(maxX*1.2D - minX*0.9D); + dMean = (meanX - minX*0.9D)/(maxX*1.2D - minX*0.9D); + } + double alphaGuess = 2.0D*dMode*dMean/(dMode - dMean); + if(alphaGuess<1.3)alphaGuess = 1.6D; + double betaGuess = alphaGuess*(1.0D - dMean)/dMean; + if(betaGuess<=1.3)betaGuess = 1.6D; + double scaleGuess = 0.0D; + if(typeFlag==0){ + scaleGuess = yPeak/Stat.betaPDF(alphaGuess, betaGuess, distribMode); + } + else{ + scaleGuess = yPeak/Stat.betaPDF(minX, maxX, alphaGuess, betaGuess, distribMode); + } + if(scaleGuess<0)scaleGuess=1; + + + // Nelder and Mead Simplex Regression for Gumbel + // Fill arrays needed by the Simplex + double[] start = new double[this.nTerms]; + double[] step = new double[this.nTerms]; + switch(typeFlag){ + case 0: start[0] = alphaGuess; //alpha + start[1] = betaGuess; //beta + if(this.scaleFlag){ + start[2] = scaleGuess; //y axis scaling factor + } + step[0] = 0.1D*start[0]; + step[1] = 0.1D*start[1]; + if(this.scaleFlag)step[2] = 0.1D*start[2]; + + // Add constraints + this.addConstraint(0,-1,1.0D); + this.addConstraint(1,-1,1.0D); + break; + case 1: start[0] = alphaGuess; //alpha + start[1] = betaGuess; //beta + start[2] = 0.9D*minX; // min + start[3] = 1.1D*maxX; // max + if(this.scaleFlag){ + start[4] = scaleGuess; //y axis scaling factor + } + step[0] = 0.1D*start[0]; + step[1] = 0.1D*start[1]; + step[2] = 0.1D*start[2]; + step[3] = 0.1D*start[3]; + if(this.scaleFlag)step[4] = 0.1D*start[4]; + + // Add constraints + this.addConstraint(0,-1,1.0D); + this.addConstraint(1,-1,1.0D); + this.addConstraint(2,+1,minX); + this.addConstraint(3,-1,maxX); + break; + + } + + // Create instance of Beta function + BetaFunction ff = new BetaFunction(); + + // Set minimum maximum type option + ff.typeFlag = typeFlag; + + // Set ordinate scaling option + ff.scaleOption = this.scaleFlag; + ff.scaleFactor = this.yScaleFactor; + + // Perform simplex regression + Object regFun3 = (Object)ff; + this.nelderMead(regFun3, start, step, this.fTol, this.nMax); + + if(allTest==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(ff); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + if(yFlag){ + // restore data + for(int i=0; i<this.nData-1; i++){ + this.yData[i]=-this.yData[i]; + } + } + } + + public void gamma(){ + this.fitGamma(0, 0); + } + + public void gammaPlot(){ + this.fitGamma(1, 0); + } + + public void gammaStandard(){ + this.fitGamma(0, 1); + } + + public void gammaStandardPlot(){ + this.fitGamma(1, 1); + } + + protected void fitGamma(int allTest, int typeFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.userSupplied = false; + switch(typeFlag){ + case 0: this.lastMethod=33; + this.nTerms=4; + break; + case 1: this.lastMethod=34; + this.nTerms=2; + break; + } + if(!this.scaleFlag)this.nTerms=this.nTerms-1; + + this.zeroCheck = false; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // check sign of y data + Double tempd=null; + ArrayList<Object> retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + double yPeak = tempd.doubleValue(); + boolean yFlag = false; + if(yPeak<0.0D){ + System.out.println("Regression.fitGamma(): This implementation of the Gamma distribution takes only positive y values\n(noise taking low values below zero are allowed)"); + System.out.println("All y values have been multiplied by -1 before fitting"); + for(int i =0; i<this.nData; i++){ + yData[i] = -yData[i]; + } + retY = Regression.dataSign(yData); + yFlag=true; + } + + // check x data + ArrayList<Object> retX = Regression.dataSign(xData[0]); + Integer tempi = null; + + // Calculate x value at peak y (estimate of the 'distribution mode') + tempi = (Integer)retY.get(5); + int peaki = tempi.intValue(); + double distribMode = xData[0][peaki]; + + // minimum value + tempd = (Double)retX.get(0); + double minX = tempd.doubleValue(); + // maximum value + tempd = (Double)retX.get(2); + double maxX = tempd.doubleValue(); + // mean value + tempd = (Double)retX.get(8); + double meanX = tempd.doubleValue(); + + + // test that data is within range + if(typeFlag==1){ + if(minX<0.0D){ + System.out.println("Regression: gammaStandard: data points must be greater than or equal to 0"); + System.out.println("method gamma used in place of method gammaStandard"); + typeFlag = 0; + this.lastMethod=33; + this.nTerms=2; + } + } + + // Calculate an estimate of the mu, beta, gamma and scale factor + double muGuess = 0.8D*minX; + if(muGuess==0.0D)muGuess = -0.1D; + double betaGuess = meanX - distribMode; + if(betaGuess<=0.0D)betaGuess = 1.0D; + double gammaGuess = (meanX + muGuess)/betaGuess; + if(typeFlag==1)gammaGuess = meanX; + if(gammaGuess<=0.0D)gammaGuess = 1.0D; + double scaleGuess = 0.0D; + if(typeFlag==0){ + scaleGuess = yPeak/Stat.gammaPDF(muGuess, betaGuess, gammaGuess, distribMode); + } + else{ + scaleGuess = yPeak/Stat.gammaPDF(gammaGuess, distribMode); + } + if(scaleGuess<0)scaleGuess=1; + + + // Nelder and Mead Simplex Regression for Gamma + // Fill arrays needed by the Simplex + double[] start = new double[this.nTerms]; + double[] step = new double[this.nTerms]; + switch(typeFlag){ + case 1: start[0] = gammaGuess; //gamma + if(this.scaleFlag){ + start[1] = scaleGuess; //y axis scaling factor + } + step[0] = 0.1D*start[0]; + if(this.scaleFlag)step[1] = 0.1D*start[1]; + + // Add constraints + this.addConstraint(0,-1,0.0D); + break; + case 0: start[0] = muGuess; // mu + start[1] = betaGuess; // beta + start[2] = gammaGuess; // gamma + if(this.scaleFlag){ + start[3] = scaleGuess; //y axis scaling factor + } + step[0] = 0.1D*start[0]; + step[1] = 0.1D*start[1]; + step[2] = 0.1D*start[2]; + if(this.scaleFlag)step[3] = 0.1D*start[3]; + + // Add constraints + this.addConstraint(1,-1,0.0D); + this.addConstraint(2,-1,0.0D); + break; + } + + // Create instance of Gamma function + GammaFunction ff = new GammaFunction(); + + // Set type option + ff.typeFlag = typeFlag; + + // Set ordinate scaling option + ff.scaleOption = this.scaleFlag; + ff.scaleFactor = this.yScaleFactor; + + // Perform simplex regression + Object regFun3 = (Object)ff; + this.nelderMead(regFun3, start, step, this.fTol, this.nMax); + + if(allTest==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(ff); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + if(yFlag){ + // restore data + for(int i=0; i<this.nData-1; i++){ + this.yData[i]=-this.yData[i]; + } + } + } + + // Fit to an Erlang Distribution + public void erlang(){ + this.fitErlang(0, 0); + } + + public void erlangPlot(){ + this.fitErlang(1, 0); + } + + protected void fitErlang(int allTest, int typeFlag){ + if(this.multipleY)throw new IllegalArgumentException("This method cannot handle multiply dimensioned y arrays"); + this.lastMethod=35; + this.userSupplied = false; + int nTerms0 = 2; // number of erlang terms + int nTerms1 = 4; // number of gamma terms - initial estimates procedure + this.nTerms = nTerms1; + if(!this.scaleFlag)this.nTerms=this.nTerms-1; + + this.zeroCheck = false; + this.degreesOfFreedom=this.nData - this.nTerms; + if(this.degreesOfFreedom<1 && !this.ignoreDofFcheck)throw new IllegalArgumentException("Degrees of freedom must be greater than 0"); + + // order data into ascending order of the abscissae + Regression.sort(this.xData[0], this.yData, this.weight); + + // check sign of y data + Double tempd=null; + ArrayList<Object> retY = Regression.dataSign(yData); + tempd = (Double)retY.get(4); + double yPeak = tempd.doubleValue(); + boolean yFlag = false; + if(yPeak<0.0D){ + System.out.println("Regression.fitGamma(): This implementation of the Erlang distribution takes only positive y values\n(noise taking low values below zero are allowed)"); + System.out.println("All y values have been multiplied by -1 before fitting"); + for(int i =0; i<this.nData; i++){ + yData[i] = -yData[i]; + } + retY = Regression.dataSign(yData); + yFlag=true; + } + + // check x data + ArrayList<Object> retX = Regression.dataSign(xData[0]); + Integer tempi = null; + + // Calculate x value at peak y (estimate of the 'distribution mode') + tempi = (Integer)retY.get(5); + int peaki = tempi.intValue(); + double distribMode = xData[0][peaki]; + + // minimum value + tempd = (Double)retX.get(0); + double minX = tempd.doubleValue(); + // maximum value + tempd = (Double)retX.get(2); + double maxX = tempd.doubleValue(); + // mean value + tempd = (Double)retX.get(8); + double meanX = tempd.doubleValue(); + + + // test that data is within range + if(minX<0.0D)throw new IllegalArgumentException("data points must be greater than or equal to 0"); + + // FIT TO GAMMA DISTRIBUTION TO OBTAIN INITIAL ESTIMATES + // Calculate an estimate of the mu, beta, gamma and scale factor + double muGuess = 0.8D*minX; + if(muGuess==0.0D)muGuess = -0.1D; + double betaGuess = meanX - distribMode; + if(betaGuess<=0.0D)betaGuess = 1.0D; + double gammaGuess = (meanX + muGuess)/betaGuess; + if(typeFlag==1)gammaGuess = meanX; + if(gammaGuess<=0.0D)gammaGuess = 1.0D; + double scaleGuess = 0.0D; + scaleGuess = yPeak/Stat.gammaPDF(muGuess, betaGuess, gammaGuess, distribMode); + if(scaleGuess<0)scaleGuess=1; + + + // Nelder and Mead Simplex Regression for Gamma + // Fill arrays needed by the Simplex + double[] start = new double[this.nTerms]; + double[] step = new double[this.nTerms]; + start[0] = muGuess; // mu + start[1] = betaGuess; // beta + start[2] = gammaGuess; // gamma + if(this.scaleFlag)start[3] = scaleGuess; //y axis scaling factor + + step[0] = 0.1D*start[0]; + step[1] = 0.1D*start[1]; + step[2] = 0.1D*start[2]; + if(this.scaleFlag)step[3] = 0.1D*start[3]; + + // Add constraints + this.addConstraint(1,-1,0.0D); + this.addConstraint(2,-1,0.0D); + + // Create instance of Gamma function + GammaFunction ff = new GammaFunction(); + + // Set type option + ff.typeFlag = typeFlag; + + // Set ordinate scaling option + ff.scaleOption = this.scaleFlag; + ff.scaleFactor = this.yScaleFactor; + + // Perform simplex regression + Object regFun3 = (Object)ff; + this.nelderMead(regFun3, start, step, this.fTol, this.nMax); + + // FIT TO ERLANG DISTRIBUTION USING GAMMA BEST ESTIMATES AS INITIAL ESTIMATES + // AND VARYING RATE PARAMETER BY UNIT STEPS + this.removeConstraints(); + + // Initial estimates + double[] bestGammaEst = this.getCoeff(); + + // Swap from Gamma dimensions to Erlang dimensions + this.nTerms = nTerms0; + start = new double[this.nTerms]; + step = new double[this.nTerms]; + if(bestGammaEst[3]<0.0)bestGammaEst[3] *= -1.0; + + // initial estimates + start[0] = 1.0D/bestGammaEst[1]; // lambda + if(this.scaleFlag)start[1] = bestGammaEst[3]; //y axis scaling factor + + step[0] = 0.1D*start[0]; + if(this.scaleFlag)step[1] = 0.1D*start[1]; + + // Add constraints + this.addConstraint(0,-1,0.0D); + + // fix initial integer rate parameter + double kay0 = Math.round(bestGammaEst[2]); + double kay = kay0; + + // Create instance of Erlang function + ErlangFunction ef = new ErlangFunction(); + + // Set ordinate scaling option + ef.scaleOption = this.scaleFlag; + ef.scaleFactor = this.yScaleFactor; + ef.kay = kay; + + // Fit stepping up + boolean testKay = true; + double ssMin = Double.NaN; + double upSS = Double.NaN; + double upKay = Double.NaN; + double kayFinal = Double.NaN; + int iStart = 1; + int ssSame = 0; + + while(testKay){ + + // Perform simplex regression + Object regFun4 = (Object)ef; + + this.nelderMead(regFun4, start, step, this.fTol, this.nMax); + double sumOfSquares = this.getSumOfSquares(); + if(iStart==1){ + iStart = 2; + ssMin = sumOfSquares; + kay = kay + 1; + start[0] = 1.0D/bestGammaEst[1]; // lambda + if(this.scaleFlag)start[1] = bestGammaEst[3]; //y axis scaling factor + step[0] = 0.1D*start[0]; + if(this.scaleFlag)step[1] = 0.1D*start[1]; + this.addConstraint(0,-1,0.0D); + ef.kay = kay; + } + else{ + if(sumOfSquares<=ssMin){ + if(sumOfSquares==ssMin){ + ssSame++; + if(ssSame==10){ + upSS = ssMin; + upKay = kay - 5; + testKay = false; + } + } + ssMin = sumOfSquares; + kay = kay + 1; + start[0] = 1.0D/bestGammaEst[1]; // lambda + if(this.scaleFlag)start[1] = bestGammaEst[3]; //y axis scaling factor + step[0] = 0.1D*start[0]; + if(this.scaleFlag)step[1] = 0.1D*start[1]; + this.addConstraint(0,-1,0.0D); + ef.kay = kay; + } + else{ + upSS = ssMin; + upKay = kay - 1; + testKay = false; + } + } + } + + if(kay0==1){ + kayFinal = upKay; + } + else{ + + // Fit stepping down + iStart = 1; + testKay = true; + ssMin = Double.NaN; + double downSS = Double.NaN; + double downKay = Double.NaN; + // initial estimates + start[0] = 1.0D/bestGammaEst[1]; // lambda + if(this.scaleFlag)start[1] = bestGammaEst[3]; //y axis scaling factor + step[0] = 0.1D*start[0]; + if(this.scaleFlag)step[1] = 0.1D*start[1]; + // Add constraints + this.addConstraint(0,-1,0.0D); + kay = kay0; + ef.kay = kay; + + while(testKay){ + + // Perform simplex regression + Object regFun5 = (Object)ef; + + this.nelderMead(regFun5, start, step, this.fTol, this.nMax); + double sumOfSquares = this.getSumOfSquares(); + if(iStart==1){ + iStart = 2; + ssMin = sumOfSquares; + kay = kay - 1; + if(Math.rint(kay)<1L){ + downSS = ssMin; + downKay = kay + 1; + testKay = false; + } + else{ + start[0] = 1.0D/bestGammaEst[1]; // lambda + if(this.scaleFlag)start[1] = bestGammaEst[3]; //y axis scaling factor + step[0] = 0.1D*start[0]; + if(this.scaleFlag)step[1] = 0.1D*start[1]; + this.addConstraint(0,-1,0.0D); + ef.kay = kay; + } + } + else{ + if(sumOfSquares<=ssMin){ + ssMin = sumOfSquares; + kay = kay - 1; + if(Math.rint(kay)<1L){ + downSS = ssMin; + downKay = kay + 1; + testKay = false; + } + else{ + start[0] = 1.0D/bestGammaEst[1]; // lambda + if(this.scaleFlag)start[1] = bestGammaEst[3]; //y axis scaling factor + step[0] = 0.1D*start[0]; + if(this.scaleFlag)step[1] = 0.1D*start[1]; + this.addConstraint(0,-1,0.0D); + ef.kay = kay; + } + } + else{ + downSS = ssMin; + downKay = kay + 1; + testKay = false; + } + } + + } + if(downSS<upSS){ + kayFinal = downKay; + } + else{ + kayFinal = upKay; + } + + } + + // Penultimate fit + // initial estimates + start[0] = 1.0D/bestGammaEst[1]; // lambda + if(this.scaleFlag)start[1] = bestGammaEst[3]; //y axis scaling factor + + step[0] = 0.1D*start[0]; + if(this.scaleFlag)step[1] = 0.1D*start[1]; + + // Add constraints + this.addConstraint(0,-1,0.0D); + + // Set function variables + ef.scaleOption = this.scaleFlag; + ef.scaleFactor = this.yScaleFactor; + ef.kay = Math.round(kayFinal); + this.kayValue = Math.round(kayFinal); + + // Perform penultimate regression + Object regFun4 = (Object)ef; + + this.nelderMead(regFun4, start, step, this.fTol, this.nMax); + double[] coeff = getCoeff(); + + // Final fit + + // initial estimates + start[0] = coeff[0]; // lambda + if(this.scaleFlag)start[1] = coeff[1]; //y axis scaling factor + + step[0] = 0.1D*start[0]; + if(this.scaleFlag)step[1] = 0.1D*start[1]; + + // Add constraints + this.addConstraint(0,-1,0.0D); + + // Set function variables + ef.scaleOption = this.scaleFlag; + ef.scaleFactor = this.yScaleFactor; + ef.kay = Math.round(kayFinal); + this.kayValue = Math.round(kayFinal); + + // Perform final regression + Object regFun5 = (Object)ef; + + this.nelderMead(regFun5, start, step, this.fTol, this.nMax); + + if(allTest==1){ + // Print results + if(!this.supressPrint)this.print(); + + // Plot results + int flag = this.plotXY(ef); + if(flag!=-2 && !this.supressYYplot)this.plotYY(); + } + + if(yFlag){ + // restore data + for(int i=0; i<this.nData-1; i++){ + this.yData[i]=-this.yData[i]; + } + } + } + + // return Erlang rate parameter (k) value + public double getKayValue(){ + return this.kayValue; + } + + + // HISTOGRAM METHODS + // Distribute data into bins to obtain histogram + // zero bin position and upper limit provided + public static double[][] histogramBins(double[] data, double binWidth, double binZero, double binUpper){ + int n = 0; // new array length + int m = data.length; // old array length; + for(int i=0; i<m; i++)if(data[i]<=binUpper)n++; + if(n!=m){ + double[] newData = new double[n]; + int j = 0; + for(int i=0; i<m; i++){ + if(data[i]<=binUpper){ + newData[j] = data[i]; + j++; + } + } + System.out.println((m-n)+" data points, above histogram upper limit, excluded in Stat.histogramBins"); + return histogramBins(newData, binWidth, binZero); + } + else{ + return histogramBins(data, binWidth, binZero); + + } + } + + // Distribute data into bins to obtain histogram + // zero bin position provided + public static double[][] histogramBins(double[] data, double binWidth, double binZero){ + double dmax = Fmath.maximum(data); + int nBins = (int) Math.ceil((dmax - binZero)/binWidth); + if(binZero+nBins*binWidth>dmax)nBins++; + int nPoints = data.length; + int[] dataCheck = new int[nPoints]; + for(int i=0; i<nPoints; i++)dataCheck[i]=0; + double[]binWall = new double[nBins+1]; + binWall[0]=binZero; + for(int i=1; i<=nBins; i++){ + binWall[i] = binWall[i-1] + binWidth; + } + double[][] binFreq = new double[2][nBins]; + for(int i=0; i<nBins; i++){ + binFreq[0][i]= (binWall[i]+binWall[i+1])/2.0D; + binFreq[1][i]= 0.0D; + } + boolean test = true; + + for(int i=0; i<nPoints; i++){ + test=true; + int j=0; + while(test){ + if(j==nBins-1){ + if(data[i]>=binWall[j] && data[i]<=binWall[j+1]*(1.0D + Regression.histTol)){ + binFreq[1][j]+= 1.0D; + dataCheck[i]=1; + test=false; + } + } + else{ + if(data[i]>=binWall[j] && data[i]<binWall[j+1]){ + binFreq[1][j]+= 1.0D; + dataCheck[i]=1; + test=false; + } + } + if(test){ + if(j==nBins-1){ + test=false; + } + else{ + j++; + } + } + } + } + int nMissed=0; + for(int i=0; i<nPoints; i++)if(dataCheck[i]==0){ + nMissed++; + System.out.println("p " + i + " " + data[i] + " " + binWall[0] + " " + binWall[nBins]); + } + if(nMissed>0)System.out.println(nMissed+" data points, outside histogram limits, excluded in Stat.histogramBins"); + return binFreq; + } + + // Distribute data into bins to obtain histogram + // zero bin position calculated + public static double[][] histogramBins(double[] data, double binWidth){ + + double dmin = Fmath.minimum(data); + double dmax = Fmath.maximum(data); + double span = dmax - dmin; + double binZero = dmin; + int nBins = (int) Math.ceil(span/binWidth); + double histoSpan = ((double)nBins)*binWidth; + double rem = histoSpan - span; + if(rem>=0){ + binZero -= rem/2.0D; + } + else{ + if(Math.abs(rem)/span>Regression.histTol){ + // readjust binWidth + boolean testBw = true; + double incr = Regression.histTol/nBins; + int iTest = 0; + while(testBw){ + binWidth += incr; + histoSpan = ((double)nBins)*binWidth; + rem = histoSpan - span; + if(rem<0){ + iTest++; + if(iTest>1000){ + testBw = false; + System.out.println("histogram method could not encompass all data within histogram\nContact Michael thomas Flanagan"); + } + } + else{ + testBw = false; + } + } + } + } + + return Regression.histogramBins(data, binWidth, binZero); + } + + +} + +// CLASSES TO EVALUATE THE SPECIAL FUNCTIONS + + +// Class to evaluate the Gausian (normal) function y = (yscale/sd.sqrt(2.pi)).exp(-0.5[(x - xmean)/sd]^2). +class GaussianFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + public double function(double[] p, double[] x){ + double yScale = scaleFactor; + if(scaleOption)yScale = p[2]; + double y = (yScale/(p[1]*Math.sqrt(2.0D*Math.PI)))*Math.exp(-0.5D*Fmath.square((x[0]-p[0])/p[1])); + return y; + } +} + +// Class to evaluate the Gausian (normal) function y = (yscale/sd.sqrt(2.pi)).exp(-0.5[(x - xmean)/sd]^2). +// Some parameters may be fixed +class GaussianFunctionFixed implements RegressionFunction{ + + public double[] param = new double[3]; + public boolean[] fixed = new boolean[3]; + + public double function(double[] p, double[] x){ + + int ii = 0; + for(int i=0; i<3; i++){ + if(!fixed[i]){ + param[i] = p[ii]; + ii++; + } + } + + double y = (param[2]/(param[1]*Math.sqrt(2.0D*Math.PI)))*Math.exp(-0.5D*Fmath.square((x[0]-param[0])/param[1])); + return y; + } +} + +// Class to evaluate the two parameter log-normal function y = (yscale/x.sigma.sqrt(2.pi)).exp(-0.5[(log(x) - mu)/sd]^2). +class LogNormalTwoParFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + public double function(double[] p, double[] x){ + double yScale = scaleFactor; + if(scaleOption)yScale = p[2]; + double y = (yScale/(x[0]*p[1]*Math.sqrt(2.0D*Math.PI)))*Math.exp(-0.5D*Fmath.square((Math.log(x[0])-p[0])/p[1])); + return y; + } +} + +// Class to evaluate the three parameter log-normal function y = (yscale/(x-alpha).beta.sqrt(2.pi)).exp(-0.5[(log((x-alpha)/gamma)/sd]^2). +class LogNormalThreeParFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + public double function(double[] p, double[] x){ + double yScale = scaleFactor; + if(scaleOption)yScale = p[3]; + double y = (yScale/((x[0]-p[0])*p[1]*Math.sqrt(2.0D*Math.PI)))*Math.exp(-0.5D*Fmath.square(Math.log((x[0]-p[0])/p[2])/p[1])); + return y; + } +} + + +// Class to evaluate the Lorentzian function +// y = (yscale/pi).(gamma/2)/((x - mu)^2+(gamma/2)^2). +class LorentzianFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + + public double function(double[] p, double[] x){ + double yScale = scaleFactor; + if(scaleOption)yScale = p[2]; + double y = (yScale/Math.PI)*(p[1]/2.0D)/(Fmath.square(x[0]-p[0])+Fmath.square(p[1]/2.0D)); + return y; + } +} + +// Class to evaluate the Poisson function +// y = yscale.(mu^k).exp(-mu)/k!. +class PoissonFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + + public double function(double[] p, double[] x){ + double yScale = scaleFactor; + if(scaleOption)yScale = p[1]; + double y = yScale*Math.pow(p[0],x[0])*Math.exp(-p[0])/Stat.factorial(x[0]); + return y; + } +} + +// Class to evaluate the Gumbel function +class GumbelFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + public int typeFlag = 0; // set to 0 -> Minimum Mode Gumbel + // reset to 1 -> Maximum Mode Gumbel + // reset to 2 -> one parameter Minimum Mode Gumbel + // reset to 3 -> one parameter Maximum Mode Gumbel + // reset to 4 -> standard Minimum Mode Gumbel + // reset to 5 -> standard Maximum Mode Gumbel + + public double function(double[] p, double[] x){ + double y=0.0D; + double arg=0.0D; + double yScale = scaleFactor; + + switch(this.typeFlag){ + case 0: + // y = yscale*(1/gamma)*exp((x-mu)/gamma)*exp(-exp((x-mu)/gamma)) + arg = (x[0]-p[0])/p[1]; + if(scaleOption)yScale = p[2]; + y = (yScale/p[1])*Math.exp(arg)*Math.exp(-(Math.exp(arg))); + break; + case 1: + // y = yscale*(1/gamma)*exp((mu-x)/gamma)*exp(-exp((mu-x)/gamma)) + arg = (p[0]-x[0])/p[1]; + if(scaleOption)yScale = p[2]; + y = (yScale/p[1])*Math.exp(arg)*Math.exp(-(Math.exp(arg))); + break; + case 2: + // y = yscale*(1/gamma)*exp((x)/gamma)*exp(-exp((x)/gamma)) + arg = x[0]/p[0]; + if(scaleOption)yScale = p[1]; + y = (yScale/p[0])*Math.exp(arg)*Math.exp(-(Math.exp(arg))); + break; + case 3: + // y = yscale*(1/gamma)*exp((-x)/gamma)*exp(-exp((-x)/gamma)) + arg = -x[0]/p[0]; + if(scaleOption)yScale = p[1]; + y = (yScale/p[0])*Math.exp(arg)*Math.exp(-(Math.exp(arg))); + break; + case 4: + // y = yscale*exp(x)*exp(-exp(x)) + if(scaleOption)yScale = p[0]; + y = yScale*Math.exp(x[0])*Math.exp(-(Math.exp(x[0]))); + break; + case 5: + // y = yscale*exp(-x)*exp(-exp(-x)) + if(scaleOption)yScale = p[0]; + y = yScale*Math.exp(-x[0])*Math.exp(-(Math.exp(-x[0]))); + break; + } + return y; + } +} + +// Class to evaluate the Frechet function +// y = yscale.(gamma/sigma)*((x - mu)/sigma)^(-gamma-1)*exp(-((x-mu)/sigma)^-gamma +class FrechetFunctionOne implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + public int typeFlag = 0; // set to 0 -> Three Parameter Frechet + // reset to 1 -> Two Parameter Frechet + // reset to 2 -> Standard Frechet + + public double function(double[] p, double[] x){ + double y = 0.0D; + boolean test = false; + double yScale = scaleFactor; + + switch(typeFlag){ + case 0: if(x[0]>=p[0]){ + double arg = (x[0] - p[0])/p[1]; + if(scaleOption)yScale = p[3]; + y = yScale*(p[2]/p[1])*Math.pow(arg,-p[2]-1.0D)*Math.exp(-Math.pow(arg,-p[2])); + } + break; + case 1: if(x[0]>=0.0D){ + double arg = x[0]/p[0]; + if(scaleOption)yScale = p[2]; + y = yScale*(p[1]/p[0])*Math.pow(arg,-p[1]-1.0D)*Math.exp(-Math.pow(arg,-p[1])); + } + break; + case 2: if(x[0]>=0.0D){ + double arg = x[0]; + if(scaleOption)yScale = p[1]; + y = yScale*p[0]*Math.pow(arg,-p[0]-1.0D)*Math.exp(-Math.pow(arg,-p[0])); + } + break; + } + return y; + } +} + +// Class to evaluate the semi-linearised Frechet function +// log(log(1/(1-Cumulative y) = gamma*log((x-mu)/sigma) +class FrechetFunctionTwo implements RegressionFunction{ + + public int typeFlag = 0; // set to 0 -> Three Parameter Frechet + // reset to 1 -> Two Parameter Frechet + // reset to 2 -> Standard Frechet + + public double function(double[] p, double[] x){ + double y=0.0D; + switch(typeFlag){ + case 0: y = -p[2]*Math.log(Math.abs(x[0]-p[0])/p[1]); + break; + case 1: y = -p[1]*Math.log(Math.abs(x[0])/p[0]); + break; + case 2: y = -p[0]*Math.log(Math.abs(x[0])); + break; + } + + return y; + } +} + +// Class to evaluate the Weibull function +// y = yscale.(gamma/sigma)*((x - mu)/sigma)^(gamma-1)*exp(-((x-mu)/sigma)^gamma +class WeibullFunctionOne implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + public int typeFlag = 0; // set to 0 -> Three Parameter Weibull + // reset to 1 -> Two Parameter Weibull + // reset to 2 -> Standard Weibull + + public double function(double[] p, double[] x){ + double y = 0.0D; + boolean test = false; + double yScale = scaleFactor; + + switch(typeFlag){ + case 0: if(x[0]>=p[0]){ + double arg = (x[0] - p[0])/p[1]; + if(scaleOption)yScale = p[3]; + y = yScale*(p[2]/p[1])*Math.pow(arg,p[2]-1.0D)*Math.exp(-Math.pow(arg,p[2])); + } + break; + case 1: if(x[0]>=0.0D){ + double arg = x[0]/p[0]; + if(scaleOption)yScale = p[2]; + y = yScale*(p[1]/p[0])*Math.pow(arg,p[1]-1.0D)*Math.exp(-Math.pow(arg,p[1])); + } + break; + case 2: if(x[0]>=0.0D){ + double arg = x[0]; + if(scaleOption)yScale = p[1]; + y = yScale*p[0]*Math.pow(arg,p[0]-1.0D)*Math.exp(-Math.pow(arg,p[0])); + } + break; + } + return y; + } +} + +// Class to evaluate the semi-linearised Weibull function +// log(log(1/(1-Cumulative y) = gamma*log((x-mu)/sigma) +class WeibullFunctionTwo implements RegressionFunction{ + + public int typeFlag = 0; // set to 0 -> Three Parameter Weibull + // reset to 1 -> Two Parameter Weibull + // reset to 2 -> Standard Weibull + + public double function(double[] p, double[] x){ + double y=0.0D; + switch(typeFlag){ + case 0: y = p[2]*Math.log(Math.abs(x[0]-p[0])/p[1]); + break; + case 1: y = p[1]*Math.log(Math.abs(x[0])/p[0]); + break; + case 2: y = p[0]*Math.log(Math.abs(x[0])); + break; + } + + return y; + } +} + +// Class to evaluate the Rayleigh function +// y = (yscale/sigma)*(x/sigma)*exp(-0.5((x-mu)/sigma)^2 +class RayleighFunctionOne implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + + public double function(double[] p, double[] x){ + double y = 0.0D; + boolean test = false; + double yScale = scaleFactor; + if(scaleOption)yScale = p[1]; + if(x[0]>=0.0D){ + double arg = x[0]/p[0]; + y = (yScale/p[0])*arg*Math.exp(-0.5D*Math.pow(arg,2)); + } + return y; + } +} + + +// Class to evaluate the semi-linearised Rayleigh function +// log(1/(1-Cumulative y) = 0.5*(x/sigma)^2 +class RayleighFunctionTwo implements RegressionFunction{ + + public double function(double[] p, double[] x){ + double y = 0.5D*Math.pow(x[0]/p[0],2); + return y; + } +} + +// class to evaluate a simple exponential function +class ExponentialSimpleFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + + public double function(double[] p, double[] x){ + double yScale = scaleFactor; + if(scaleOption)yScale = p[1]; + double y = yScale*Math.exp(p[0]*x[0]); + return y; + } +} + +// class to evaluate multiple exponentials function +class ExponentialMultipleFunction implements RegressionFunction{ + + public int nExps = 0; + + public double function(double[] p, double[] x){ + double y = 0; + for(int i=0; i<nExps; i+=2){ + y += p[i]*Math.exp(p[i+1]*x[0]); + } + return y; + } +} + +// class to evaluate a exponential distribution function +class ExponentialFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + public int typeFlag = 0; // set to 0 -> Two Parameter Exponential + // reset to 1 -> One Parameter Exponential + // reset to 2 -> Standard Exponential + + public double function(double[] p, double[] x){ + double y = 0.0D; + boolean test = false; + double yScale = scaleFactor; + + switch(typeFlag){ + case 0: if(x[0]>=p[0]){ + if(scaleOption)yScale = p[2]; + double arg = (x[0] - p[0])/p[1]; + y = (yScale/p[1])*Math.exp(-arg); + } + break; + case 1: if(x[0]>=0.0D){ + double arg = x[0]/p[0]; + if(scaleOption)yScale = p[1]; + y = (yScale/p[0])*Math.exp(-arg); + } + break; + case 2: if(x[0]>=0.0D){ + double arg = x[0]; + if(scaleOption)yScale = p[0]; + y = yScale*Math.exp(-arg); + } + break; + } + return y; + } +} + +// class to evaluate a Pareto scaled pdf +class ParetoFunctionOne implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + public int typeFlag = 0; // set to 3 -> Shifted Pareto + // set to 2 -> Two Parameter Pareto + // set to 1 -> One Parameter Pareto + + public double function(double[] p, double[] x){ + double y = 0.0D; + boolean test = false; + double yScale = scaleFactor; + + switch(typeFlag){ + case 3: if(x[0]>=p[1]+p[2]){ + if(scaleOption)yScale = p[3]; + y = yScale*p[0]*Math.pow(p[1],p[0])/Math.pow((x[0]-p[2]),p[0]+1.0D); + } + break; + case 2: if(x[0]>=p[1]){ + if(scaleOption)yScale = p[2]; + y = yScale*p[0]*Math.pow(p[1],p[0])/Math.pow(x[0],p[0]+1.0D); + } + break; + case 1: if(x[0]>=1.0D){ + double arg = x[0]/p[0]; + if(scaleOption)yScale = p[1]; + y = yScale*p[0]/Math.pow(x[0],p[0]+1.0D); + } + break; + } + return y; + } +} + +// class to evaluate a Pareto cdf +class ParetoFunctionTwo implements RegressionFunction{ + + public int typeFlag = 0; // set to 3 -> Shifted Pareto + // set to 2 -> Two Parameter Pareto + // set to 1 -> One Parameter Pareto + + public double function(double[] p, double[] x){ + double y = 0.0D; + switch(typeFlag){ + case 3: if(x[0]>=p[1]+p[2]){ + y = 1.0D - Math.pow(p[1]/(x[0]-p[2]),p[0]); + } + break; + case 2: if(x[0]>=p[1]){ + y = 1.0D - Math.pow(p[1]/x[0],p[0]); + } + break; + case 1: if(x[0]>=1.0D){ + y = 1.0D - Math.pow(1.0D/x[0],p[0]); + } + break; + } + return y; + } +} + +// class to evaluate a Sigmoidal threshold function +class SigmoidThresholdFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + + public double function(double[] p, double[] x){ + double yScale = scaleFactor; + if(scaleOption)yScale = p[2]; + double y = yScale/(1.0D + Math.exp(-p[0]*(x[0] - p[1]))); + return y; + } +} + +// class to evaluate a Rectangular Hyberbola +class RectangularHyperbolaFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + + public double function(double[] p, double[] x){ + double yScale = scaleFactor; + if(scaleOption)yScale = p[2]; + double y = yScale*x[0]/(p[0] + x[0]); + return y; + } + +} + +// class to evaluate a scaled Heaviside Step Function +class StepFunctionFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + + public double function(double[] p, double[] x){ + double yScale = scaleFactor; + if(scaleOption)yScale = p[1]; + double y = 0.0D; + if(x[0]>p[0])y = yScale; + return y; + } +} + +// class to evaluate a Hill or Sips sigmoidal function +class SigmoidHillSipsFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + + public double function(double[] p, double[] x){ + double yScale = scaleFactor; + if(scaleOption)yScale = p[2]; + double xterm = Math.pow(x[0],p[1]); + double y = yScale*xterm/(Math.pow(p[0], p[1]) + xterm); + return y; + } +} + +// Class to evaluate the Logistic probability function y = yscale*exp(-(x-mu)/beta)/(beta*(1 + exp(-(x-mu)/beta))^2. +class LogisticFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + public double function(double[] p, double[] x){ + double yScale = scaleFactor; + if(scaleOption)yScale = p[2]; + double y = yScale*Fmath.square(Fmath.sech((x[0] - p[0])/(2.0D*p[1])))/(4.0D*p[1]); + return y; + } +} + +// class to evaluate a Beta scaled pdf +class BetaFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + public int typeFlag = 0; // set to 0 -> Beta Distibution - [0, 1] interval + // set to 1 -> Beta Distibution - [min, max] interval + + public double function(double[] p, double[] x){ + double y = 0.0D; + boolean test = false; + double yScale = scaleFactor; + + switch(typeFlag){ + case 0: if(scaleOption)yScale = p[2]; + y = yScale*Math.pow(x[0],p[0]-1.0D)*Math.pow(1.0D-x[0],p[1]-1.0D)/Stat.betaFunction(p[0],p[1]); + break; + case 1: if(scaleOption)yScale = p[4]; + y = yScale*Math.pow(x[0]-p[2],p[0]-1.0D)*Math.pow(p[3]-x[0],p[1]-1.0D)/Stat.betaFunction(p[0],p[1]); + y = y/Math.pow(p[3]-p[2],p[0]+p[1]-1.0D); + break; + } + return y; + } +} + +// class to evaluate a Gamma scaled pdf +class GammaFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + public int typeFlag = 0; // set to 0 -> Three parameter Gamma Distribution + // set to 1 -> Standard Gamma Distribution + + public double function(double[] p, double[] x){ + double y = 0.0D; + boolean test = false; + double yScale = scaleFactor; + + switch(typeFlag){ + case 0: if(scaleOption)yScale = p[3]; + double xTerm = (x[0] - p[0])/p[1]; + y = yScale*Math.pow(xTerm,p[2]-1.0D)*Math.exp(-xTerm)/(p[1]*Stat.gammaFunction(p[2])); + break; + case 1: if(scaleOption)yScale = p[1]; + y = yScale*Math.pow(x[0],p[0]-1.0D)*Math.exp(-x[0])/Stat.gammaFunction(p[0]); + break; + } + return y; + } +} + +// class to evaluate a Erlang scaled pdf +// rate parameter is fixed +class ErlangFunction implements RegressionFunction{ + public boolean scaleOption = true; + public double scaleFactor = 1.0D; + public double kay = 1.0D; // rate parameter + + public double function(double[] p, double[] x){ + boolean test = false; + double yScale = scaleFactor; + + if(scaleOption)yScale = p[1]; + + double y = kay*Math.log(p[0]) + (kay - 1)*Math.log(x[0]) - x[0]*p[0] - Fmath.logFactorial(kay - 1); + y = yScale*Math.exp(y); + + return y; + } +} + +// class to evaluate a EC50 function +class EC50Function implements RegressionFunction{ + + public double function(double[] p, double[] x){ + double y = p[0] + (p[1] - p[0])/(1.0D + Math.pow(x[0]/p[2], p[3])); + return y; + } +} + +// class to evaluate a LogEC50 function +class LogEC50Function implements RegressionFunction{ + + public double function(double[] p, double[] x){ + double y = p[0] + (p[1] - p[0])/(1.0D + Math.pow(10.0D, (p[2] - x[0])*p[3])); + return y; + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/analysis/RegressionDerivativeFunction.java b/src/main/java/flanagan/analysis/RegressionDerivativeFunction.java new file mode 100755 index 0000000000000000000000000000000000000000..7a4765d5b07898c6520217ada4d45f2955725171 --- /dev/null +++ b/src/main/java/flanagan/analysis/RegressionDerivativeFunction.java @@ -0,0 +1,50 @@ +/* +* Interface RegressionFunction +* +* The sum of squares function needed by the +* non-linear regression methods in the class Regression +* is supplied by means of this interface, RegressionFunction +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: October 2008 +* MODIFIED: +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Regression.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2008 +* +* PERMISSION TO COPY: +* +* Redistributions of this source code, or parts of, must retain the above +* copyright notice, this list of conditions and the following disclaimer. +* +* Redistribution in binary form of all or parts of this class, must reproduce +* the above copyright, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the distribution. +* +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all +* copies and associated documentation or publications. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + + +package flanagan.analysis; + +// Interface for Regression class +// Derivative function for non-linear regression methods +// i = index of parameter a in dy/da[i] + +public interface RegressionDerivativeFunction{ + double function(double[]param, double[] x, int i); +} diff --git a/src/main/java/flanagan/analysis/RegressionDerivativeFunction2.java b/src/main/java/flanagan/analysis/RegressionDerivativeFunction2.java new file mode 100755 index 0000000000000000000000000000000000000000..1f2fbfb60dfc6d88aa950026397378855b38d66f --- /dev/null +++ b/src/main/java/flanagan/analysis/RegressionDerivativeFunction2.java @@ -0,0 +1,50 @@ +/* +* Interface RegressionFunction2 +* +* The sum of squares function, for multiple y array option, needed +* by the non-linear regression methods in the class Regression +* is supplied by means of this interface, RegressionFunction2 +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: October 2008 +* MODIFIED: +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Regression.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2008 +* +* PERMISSION TO COPY: +* +* Redistributions of this source code, or parts of, must retain the above +* copyright notice, this list of conditions and the following disclaimer. +* +* Redistribution in binary form of all or parts of this class, must reproduce +* the above copyright, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the distribution. +* +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all +* copies and associated documentation or publications. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + + +package flanagan.analysis; + +// Interface for Regression class +// Derivative function for non-linear regression methods +// i = index of parameter a in dy/da[i] +// k = index of the data x value +public interface RegressionDerivativeFunction2{ + double function(double[]param, double[] x, int i, int k); +} diff --git a/src/main/java/flanagan/analysis/RegressionFunction.java b/src/main/java/flanagan/analysis/RegressionFunction.java new file mode 100755 index 0000000000000000000000000000000000000000..008973729bc663f3f4fd3000e141de9fc4d3ff12 --- /dev/null +++ b/src/main/java/flanagan/analysis/RegressionFunction.java @@ -0,0 +1,48 @@ +/* +* Interface RegressionFunction +* +* The sum of squares function needed by the +* non-linear regression methods in the class Regression +* is supplied by means of this interface, RegressionFunction +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: February 2002 +* MODIFIED: 14 April 2004 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Regression.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2008 +* +* PERMISSION TO COPY: +* +* Redistributions of this source code, or parts of, must retain the above +* copyright notice, this list of conditions and the following disclaimer. +* +* Redistribution in binary form of all or parts of this class, must reproduce +* the above copyright, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the distribution. +* +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all +* copies and associated documentation or publications. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + + +package flanagan.analysis; + +// Interface for Regression class +// Sum of squares function for non-linear regression methods +public interface RegressionFunction{ + double function(double[]param, double[] x); +} diff --git a/src/main/java/flanagan/analysis/RegressionFunction2.java b/src/main/java/flanagan/analysis/RegressionFunction2.java new file mode 100755 index 0000000000000000000000000000000000000000..ace09243dd8a70e71f9364c5d1f700a7a6c6e55e --- /dev/null +++ b/src/main/java/flanagan/analysis/RegressionFunction2.java @@ -0,0 +1,48 @@ +/* +* Interface RegressionFunction2 +* +* The sum of squares function, for multiple y array option, needed +* by the non-linear regression methods in the class Regression +* is supplied by means of this interface, RegressionFunction2 +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: February 2002 +* MODIFIED: 14 April 2004 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Regression.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2008 +* +* PERMISSION TO COPY: +* +* Redistributions of this source code, or parts of, must retain the above +* copyright notice, this list of conditions and the following disclaimer. +* +* Redistribution in binary form of all or parts of this class, must reproduce +* the above copyright, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the distribution. +* +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all +* copies and associated documentation or publications. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + + +package flanagan.analysis; + +// Interface for Regression class +// Sum of squares function for non-linear regression methods +public interface RegressionFunction2{ + double function(double[]param, double[] x, int i); +} diff --git a/src/main/java/flanagan/analysis/Scores.java b/src/main/java/flanagan/analysis/Scores.java new file mode 100755 index 0000000000000000000000000000000000000000..eefb655933dc53b884a0b6e6d4580b0581e9b62d --- /dev/null +++ b/src/main/java/flanagan/analysis/Scores.java @@ -0,0 +1,4784 @@ +/* +* CLASS: Scores +* +* USAGE: Class for entering scores (responses) for several items, +* e.g. questionnaire questions, examination questions +* This is superclass for several educational statistics classes, +* e.g. Cronbach +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: October 2008 +* AMENDED: 12 October 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* http://www.ee.ucl.ac.uk/~mflanaga/java/Cronbach.html +* +* Copyright (c) 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + + +package flanagan.analysis; + +import java.util.*; +import java.text.*; + +import flanagan.math.*; +import flanagan.io.*; +import flanagan.analysis.*; +import flanagan.plot.*; + + +public class Scores{ + + protected String[] title =null; // title + protected int titleLines = 0; // number of lines in the title + + protected String inputFilename = null; // input file name if input data read from file + protected String outputFilename = null; // output file name if output written to file + protected int fileOption = 1; // type of file option + // option = 1 - text file (.txt) // option = 2 - MS Excel file (.xls) + protected boolean fileOptionSet = false; // = true if fileOption changed by user + protected String[] fileExtensions = {".txt", ".xls"}; // Output file extensions + protected boolean fileNumberingSet = false; // = output file of identical name to existing file overwrites existing file + // = true incremented number added to output file name to prevent overwriting + protected int trunc = 6; // number of decimal places in output data + + protected int originalDataType = -1; // = 1 - String[][] (including read from file); + // = 2 - double[][] + // = 3 - Matrix + // = 4 - float[][] + // = 5 - int[][] + // = 6 - char[][] + // = 7 - boolean[][] + + protected int originalDataOrder = -1; // = 0 - matrix columns = responses of a person + // = 1 - matrix rows = responses of a person to each item + + protected Object originalData = null; // Original data as entered + + protected double[][]scores0 = null; // individual scores - after any 'no response' deletions or replacements + // arranged as rows of scores for each item + // e.g. scores0[0][0] to scores0[0][nIndividuals-1] = scores for each person in turn for the first item + // scores0[1][0] to scores0[1][nIndividuals-1] = scores for each person in turn for the second item + // etc. + protected double[][]originalScores0 = null; // scores0 before any 'no response' deletions or replacements + protected double[][]standardizedScores0 = null; // standardized scores0 + + protected double[][]scores1 = null; // individual scores - after any 'no response' deletions or replacements + // arranged as rows of scores for each person + // e.g. scores1[0][0] to scores1[0][nItems-1] = scores for each item in turn for the first person + // scores1[1][0] to scores1[1][nItems-1] = scores for each item in turn for the second person + // etc. + protected double[][]originalScores1 = null; // scores1 before any 'no response' deletions or replacements + protected double[][]standardizedScores1 = null; // standardized scores1 + + protected boolean dataEntered = false; // = true when scores entered + protected boolean dataPreprocessed = false; // = true when scores have been preprocessed + + protected int nItems = 0; // number of items, after any deletions + protected int originalNitems = 0; // original number of items + protected String[] itemNames = null; // names of the items + protected String[] originalItemNames = null; // list of item names before any deletions + protected boolean itemNamesSet = false; // = true when item names entered + + protected int nPersons = 0; // number of persons, after any deletions + protected int originalNpersons = 0; // original number of persons + + protected int nScores = 0; // total number of scores, after any deletions + protected int originalNscores = 0; // original total number of scores + + protected String otherFalse = null; // false value for dichotomous data if one of the default values + protected String otherTrue = null; // true value for dichotomous data if one of the default values + // default values: a numeral, true (ignoring case), false (ignoring case), yes (ignoring case), no (ignoring case) + protected boolean otherDichotomousDataSet = false; // = true if user sets an alternative dichotomous pair + protected boolean[] dichotomous = null; // true if the data in an item is dichotomous + protected double[] dichotomousPercentage = null; // percentage of responses in an item that are dichotomous + protected boolean dichotomousOverall = false; // true if all the data is dichotomous + protected boolean dichotomousCheckDone = false; // true if check for dichotomous data performed + + protected boolean letterToNumeralSet = false; // = true if user set the letter to numeral option allowing alphabetic response input + + protected boolean ignoreNoResponseRequests = false; // = true - requests for 'no resonse' options are not displayed + + protected double itemDeletionPercentage = 100.0; // percentage of no responses allowed within an item before the item is deleted + protected boolean itemDeletionPercentageSet = false; // = true when this percentage is reset + + protected double personDeletionPercentage = 0.0; // percentage of no responses allowed within a person's responses before the person is deleted + protected boolean personDeletionPercentageSet = false; // = true when this percentage is reset + + protected int replacementOption = 3; // option flag for a missing response if deletion not carried out + // option = 1 - score replaced by zero + // option = 2 - score replaced by person's mean + // option = 3 - score replaced by item mean (default option) + // option = 4 - score replaced by overall mean + // option = 5 - user supplied score for each 'no response' + + protected String[] replacementOptionNames = {"score replaced by zero", "score replaced by person's mean", "score replaced by item mean", "score replaced by overall mean", "user supplied score for each 'no response'"}; + + protected boolean replacementOptionSet = false; // = true when replacementOption set + protected boolean allNoResponseOptionsSet = false; // = true when personDeletionPercentageSet, itemDeletionPercentageSet and replacementOptionSet are all true + protected boolean noResponseHandlingSet = false; // = true when 'no response' handling options are all set + + protected int nNaN = 0; // number of 'no responses' (initially equated to NaN) + protected boolean[] deletedItems = null; // = true if item corresponding to the deletedItems array index has been deleted, false otherwise + protected int nDeletedItems = 0; // number of deleted items + protected int[] deletedItemsIndices = null; // indices of the deleted items + protected int[] itemIndices = null; // indices of items in original data before deletions + + protected boolean[] deletedPersons = null; // = true if person corresponding to the deletedItems array index has been deleted, false otherwise + // person deleted if no response in all items,then deleted irrespective of missing response option choice + protected int nDeletedPersons = 0; // number of deleted persons + protected int[] deletedPersonsIndices = null; // indices of the deleted persons + protected int[] personIndices = null; // indices of persons in original data before deletions + + protected int nReplacements = 0; // number of 'no response' replacements + protected String[] replacementIndices = null; // indices of 'no response' replacements + + protected double[] rawItemMeans = null; // means of the responses in each item (raw data) + protected double rawItemMeansMean = Double.NaN; // mean of the means of the responses in each item (raw data) + protected double rawItemMeansSd = Double.NaN; // standard deviation of the means of the responses in each item (raw data) + protected double rawItemMeansVar = Double.NaN; // variance of the means of the responses in each item (raw data) + protected double rawItemMeansMin = Double.NaN; // minimum of the means of the responses in each item (raw data) + protected double rawItemMeansMax = Double.NaN; // maximum of the means of the responses in each item (raw data) + protected double rawItemMeansRange = Double.NaN; // range of the means of the responses in each item (raw data) + + protected double[] rawItemStandardDeviations = null; // standard deviations of the responses in each item (raw data) + protected double rawItemStandardDeviationsMean = Double.NaN; // mean of the StandardDeviations of the responses in each item (raw data) + protected double rawItemStandardDeviationsSd = Double.NaN; // standard deviation of the Standard Deviations of the responses in each item (raw data) + protected double rawItemStandardDeviationsVar = Double.NaN; // variance of the Standard Deviations of the responses in each item (raw data) + protected double rawItemStandardDeviationsMin = Double.NaN; // minimum of the Standard Deviations of the responses in each item (raw data) + protected double rawItemStandardDeviationsMax = Double.NaN; // maximum of the Standard Deviations of the responses in each item (raw data) + protected double rawItemStandardDeviationsRange = Double.NaN; // range of the Standard Deviations of the responses in each item (raw data) + + protected double[] rawItemVariances = null; // variances of the responses in each item (raw data) + protected double rawItemVariancesMean = Double.NaN; // mean of the Variances of the responses in each item (raw data) + protected double rawItemVariancesSd = Double.NaN; // standard deviation of the Variances of the responses in each item (raw data) + protected double rawItemVariancesVar = Double.NaN; // variance of the Variances of the responses in each item (raw data) + protected double rawItemVariancesMin = Double.NaN; // minimum of the Variances of the responses in each item (raw data) + protected double rawItemVariancesMax = Double.NaN; // maximum of the Variances of the responses in each item (raw data) + protected double rawItemVariancesRange = Double.NaN; // range of the Variances of the responses in each item (raw data) + + protected double[] rawItemMinima = null; // minima of the responses in each item (raw data) + protected double rawItemMinimaMean = Double.NaN; // mean of the Minima of the responses in each item (raw data) + protected double rawItemMinimaSd = Double.NaN; // standard deviation of the Minima of the responses in each item (raw data) + protected double rawItemMinimaVar = Double.NaN; // variance of the Minima of the responses in each item (raw data) + protected double rawItemMinimaMin = Double.NaN; // minimum of the Minima of the responses in each item (raw data) + protected double rawItemMinimaMax = Double.NaN; // maximum of the Minima of the responses in each item (raw data) + protected double rawItemMinimaRange = Double.NaN; // range of the Minima of the responses in each item (raw data) + + protected double[] rawItemMaxima = null; // maxima of the responses in each item (raw data) + protected double rawItemMaximaMean = Double.NaN; // mean of the Maxima of the responses in each item (raw data) + protected double rawItemMaximaSd = Double.NaN; // standard deviation of the Maxima of the responses in each item (raw data) + protected double rawItemMaximaVar = Double.NaN; // variance of the Maxima of the responses in each item (raw data) + protected double rawItemMaximaMin = Double.NaN; // minimum of the Maxima of the responses in each item (raw data) + protected double rawItemMaximaMax = Double.NaN; // maximum of the Maxima of the responses in each item (raw data) + protected double rawItemMaximaRange = Double.NaN; // range of the Maxima of the responses in each item (raw data) + + protected double[] rawItemRanges = null; // Ranges of the responses in each item (raw data) + protected double rawItemRangesMean = Double.NaN; // mean of the Ranges of the responses in each item (raw data) + protected double rawItemRangesSd = Double.NaN; // standard deviation of the Ranges of the responses in each item (raw data) + protected double rawItemRangesVar = Double.NaN; // variance of the Ranges of the responses in each item (raw data) + protected double rawItemRangesMin = Double.NaN; // minimum of the Ranges of the responses in each item (raw data) + protected double rawItemRangesMax = Double.NaN; // maximum of the Ranges of the responses in each item (raw data) + protected double rawItemRangesRange = Double.NaN; // range of the Ranges of the responses in each item (raw data) + + protected double[] rawItemTotals = null; // totals of the responses in each item (raw data) + protected double rawItemTotalsMean = Double.NaN; // mean of the Totals of the responses in each item (raw data) + protected double rawItemTotalsSd = Double.NaN; // standard deviation of the Totals of the responses in each item (raw data) + protected double rawItemTotalsVar = Double.NaN; // variance of the Totals of the responses in each item (raw data) + protected double rawItemTotalsMin = Double.NaN; // minimum of the Totals of the responses in each item (raw data) + protected double rawItemTotalsMax = Double.NaN; // maximum of the Totals of the responses in each item (raw data) + protected double rawItemTotalsRange = Double.NaN; // range of the Totals of the responses in each item (raw data) + + protected double[] rawItemMedians = null; // medians of the sorted responses in each item (raw data) + protected double rawItemMediansMean = Double.NaN; // mean of the Medians of the responses in each item (raw data) + protected double rawItemMediansSd = Double.NaN; // standard deviation of the Medians of the responses in each item (raw data) + protected double rawItemMediansVar = Double.NaN; // variance of the Medians of the responses in each item (raw data) + protected double rawItemMediansMin = Double.NaN; // minimum of the Medians of the responses in each item (raw data) + protected double rawItemMediansMax = Double.NaN; // maximum of the Medians of the responses in each item (raw data) + protected double rawItemMediansRange = Double.NaN; // range of the Medians of the responses in each item (raw data) + + protected double[] rawItemMomentSkewness = null; // Moment skewness of the responses in each item (raw data) + protected double[] rawItemMedianSkewness = null; // Median skewness of the responses in each item (raw data) + protected double[] rawItemQuartileSkewness = null; // Quartile skewness of the responses in each item (raw data) + protected double[] rawItemKurtosisExcess = null; // Kurtosis excess of the responses in each item (raw data) + + protected double[] rawPersonMeans = null; // means of the responses for each person (raw data) + protected double[] rawPersonStandardDeviations = null; // standard deviations of the responses for each person (raw data) + protected double[] rawPersonVariances = null; // variances of the responses for each person (raw data) + protected double[] rawPersonMinima = null; // minima of the responses for each person (raw data) + protected double[] rawPersonMaxima = null; // maxima of the responses for each person (raw data) + protected double[] rawPersonRanges = null; // ranges of the responses for each person (raw data) + protected double[] rawPersonTotals = null; // totals of the responses for each person (raw data) + + protected double rawAllResponsesMean = Double.NaN; // mean of all the responses (raw data) + protected double rawAllResponsesStandardDeviation = Double.NaN; // standard deviation of all the responses (raw data) + protected double rawAllResponsesVariance = Double.NaN; // variance of all the responses (raw data) + protected double rawAllResponsesMinimum = Double.NaN; // minimum of all the responses (raw data) + protected double rawAllResponsesMaximum = Double.NaN; // maximum of all the responses (raw data) + protected double rawAllResponsesRange = Double.NaN; // ranges of all the responses (raw data) + protected double rawAllResponsesTotal = Double.NaN; // total of all the responses (raw data) + + protected double[][] rawCovariances = null; // covariances between items (raw data) + protected double[][] rawCorrelationCoefficients = null; // correlation coefficients between items (raw data) + protected double[] rawRhosWithTotal = null; // correlation coefficient of an item with the itemtotals (raw data) + protected double rawMeanRhoWithTotals = Double.NaN; // average inter-item correlation coeffecient including totals (raw data) + protected double rawStandardDeviationRhoWithTotals = Double.NaN; // standard deviation of inter-item correlation coeffecient including totals (raw data) + protected double rawMeanRhoWithoutTotals = Double.NaN; // average inter-item correlation coeffecient excluding totals (raw data) + protected double rawStandardDeviationRhoWithoutTotals = Double.NaN; // standard deviation of inter-item correlation coeffecient excluding totals (raw data) + + protected double[] standardizedItemMeans = null; // means of the responses in each item (standardized data) + protected double standardizedItemMeansMean = Double.NaN; // mean of the means of the responses in each item (standardized data) + protected double standardizedItemMeansSd = Double.NaN; // standard deviation of the means of the responses in each item (standardized data) + protected double standardizedItemMeansVar = Double.NaN; // variance of the means of the responses in each item (standardized data) + protected double standardizedItemMeansMin = Double.NaN; // minimum of the means of the responses in each item (standardized data) + protected double standardizedItemMeansMax = Double.NaN; // maximum of the means of the responses in each item (standardized data) + protected double standardizedItemMeansRange = Double.NaN; // range of the means of the responses in each item (standardized data) + + protected double[] standardizedItemStandardDeviations = null; // standard deviations of the responses in each item (standardized data) + protected double standardizedItemStandardDeviationsMean = Double.NaN; // mean of the Standard Deviations of the responses in each item (standardized data) + protected double standardizedItemStandardDeviationsSd = Double.NaN; // standard deviation of the Standard Deviations of the responses in each item (standardized data) + protected double standardizedItemStandardDeviationsVar = Double.NaN; // variance of the Standard Deviations of the responses in each item (standardized data) + protected double standardizedItemStandardDeviationsMin = Double.NaN; // minimum of the Standard Deviations of the responses in each item (standardized data) + protected double standardizedItemStandardDeviationsMax = Double.NaN; // maximum of the Standard Deviations of the responses in each item (standardized data) + protected double standardizedItemStandardDeviationsRange = Double.NaN; // range of the Standard Deviations of the responses in each item (standardized data) + + protected double[] standardizedItemVariances = null; // variances of the responses in each item (standardized data) + protected double standardizedItemVariancesMean = Double.NaN; // mean of the Variances of the responses in each item (standardized data) + protected double standardizedItemVariancesSd = Double.NaN; // standard deviation of the Variances of the responses in each item (standardized data) + protected double standardizedItemVariancesVar = Double.NaN; // variance of the Variances of the responses in each item (standardized data) + protected double standardizedItemVariancesMin = Double.NaN; // minimum of the Variances of the responses in each item (standardized data) + protected double standardizedItemVariancesMax = Double.NaN; // maximum of the Variances of the responses in each item (standardized data) + protected double standardizedItemVariancesRange = Double.NaN; // range of the Variances of the responses in each item (standardized data) + + protected double[] standardizedItemMinima = null; // minima of the responses in each item (standardized data) + protected double standardizedItemMinimaMean = Double.NaN; // mean of the Minima of the responses in each item (standardized data) + protected double standardizedItemMinimaSd = Double.NaN; // standard deviation of the Minima of the responses in each item (standardized data) + protected double standardizedItemMinimaVar = Double.NaN; // variance of the Minima of the responses in each item (standardized data) + protected double standardizedItemMinimaMin = Double.NaN; // minimum of the Minima of the responses in each item (standardized data) + protected double standardizedItemMinimaMax = Double.NaN; // maximum of the Minima of the responses in each item (standardized data) + protected double standardizedItemMinimaRange = Double.NaN; // range of the Minima of the responses in each item (standardized data) + + protected double[] standardizedItemMaxima = null; // maxima of the responses in each item (standardized data) + protected double standardizedItemMaximaMean = Double.NaN; // mean of the Maxima of the responses in each item (standardized data) + protected double standardizedItemMaximaSd = Double.NaN; // standard deviation of the Maxima of the responses in each item (standardized data) + protected double standardizedItemMaximaVar = Double.NaN; // variance of the Maxima of the responses in each item (standardized data) + protected double standardizedItemMaximaMin = Double.NaN; // minimum of the Maxima of the responses in each item (standardized data) + protected double standardizedItemMaximaMax = Double.NaN; // maximum of the Maxima of the responses in each item (standardized data) + protected double standardizedItemMaximaRange = Double.NaN; // range of the Maxima of the responses in each item (standardized data) + + protected double[] standardizedItemRanges = null; // Ranges of the responses in each item (standardized data) + protected double standardizedItemRangesMean = Double.NaN; // mean of the Ranges of the responses in each item (standardized data) + protected double standardizedItemRangesSd = Double.NaN; // standard deviation of the Ranges of the responses in each item (standardized data) + protected double standardizedItemRangesVar = Double.NaN; // variance of the Ranges of the responses in each item (standardized data) + protected double standardizedItemRangesMin = Double.NaN; // minimum of the Ranges of the responses in each item (standardized data) + protected double standardizedItemRangesMax = Double.NaN; // maximum of the Ranges of the responses in each item (standardized data) + protected double standardizedItemRangesRange = Double.NaN; // range of the Ranges of the responses in each item (standardized data) + + protected double[] standardizedItemTotals = null; // totals of the responses in each item (standardized data) + protected double standardizedItemTotalsMean = Double.NaN; // mean of the Totals of the responses in each item (standardized data) + protected double standardizedItemTotalsSd = Double.NaN; // standard deviation of the Totals of the responses in each item (standardized data) + protected double standardizedItemTotalsVar = Double.NaN; // variance of the Totals of the responses in each item (standardized data) + protected double standardizedItemTotalsMin = Double.NaN; // minimum of the Totals of the responses in each item (standardized data) + protected double standardizedItemTotalsMax = Double.NaN; // maximum of the Totals of the responses in each item (standardized data) + protected double standardizedItemTotalsRange = Double.NaN; // range of the Totals of the responses in each item (standardized data) + + protected double[] standardizedItemMedians = null; // medians of the sorted responses in each item (standardized data) + protected double standardizedItemMediansMean = Double.NaN; // mean of the Medians of the responses in each item (standardized data) + protected double standardizedItemMediansSd = Double.NaN; // standard deviation of the Medians of the responses in each item (standardized data) + protected double standardizedItemMediansVar = Double.NaN; // variance of the Medians of the responses in each item (standardized data) + protected double standardizedItemMediansMin = Double.NaN; // minimum of the Medians of the responses in each item (standardized data) + protected double standardizedItemMediansMax = Double.NaN; // maximum of the Medians of the responses in each item (standardized data) + protected double standardizedItemMediansRange = Double.NaN; // range of the Medians of the responses in each item (standardized data) + + protected double[] standardizedItemMomentSkewness = null; // Moment skewness of the responses in each item (standardized data) + protected double[] standardizedItemMedianSkewness = null; // Median skewness of the responses in each item (standardized data) + protected double[] standardizedItemQuartileSkewness = null; // Quartile skewness of the responses in each item (standardized data) + protected double[] standardizedItemKurtosisExcess = null; // Kurtosis excess of the responses in each item (standardized data) + + protected double[] standardizedPersonMeans = null; // mean of the responses for each person (standardized data) + protected double[] standardizedPersonStandardDeviations = null; // standard deviation of the responses for each person (standardized data) + protected double[] standardizedPersonVariances = null; // variance of the responses for each person (standardized data) + protected double[] standardizedPersonMinima = null; // minima of the responses for each person (standardized data) + protected double[] standardizedPersonMaxima = null; // maxima of the responses for each person (standardized data) + protected double[] standardizedPersonRanges = null; // ranges of the responses for each person (standardized data) + protected double[] standardizedPersonTotals = null; // totals of the responses for each person (standardized data) + + protected double standardizedAllResponsesMean = Double.NaN; // means of all the responses (standardized data) + protected double standardizedAllResponsesStandardDeviation = Double.NaN; // standard deviations of all the responses (standardized data) + protected double standardizedAllResponsesVariance = Double.NaN; // variances of all the responses (standardized data) + protected double standardizedAllResponsesMinimum = Double.NaN; // minimum of all the responses (standardized data) + protected double standardizedAllResponsesMaximum = Double.NaN; // maximum of all the responses (standardized data) + protected double standardizedAllResponsesRange = Double.NaN; // range of all the responses (standardized data) + protected double standardizedAllResponsesTotal = Double.NaN; // total of all the responses (standardized data) + + protected double[][] standardizedCovariances = null; // covariances between items (standardized data) + protected double[][] standardizedCorrelationCoefficients = null; // correlation coefficients between items (standardized data) + protected double[] standardizedRhosWithTotal = null; // correlation coefficient of an item with the itemtotals (standardized data) + protected double standardizedMeanRhoWithTotals = Double.NaN; // average inter-item correlation coeffecient including totals (standardized data) + protected double standardizedStandardDeviationRhoWithTotals = Double.NaN; // standard deviation of nter-item correlation coeffecient including totals (standardized data) + protected double standardizedMeanRhoWithoutTotals = Double.NaN; // average inter-item correlation coeffecient excluding totals (standardized data) + protected double standardizedStandardDeviationRhoWithoutTotals = Double.NaN; // standard deviation of inter-item correlation coeffecient excluding totals (standardized data) + + protected boolean variancesCalculated = false; // = true when means, variances and standard deviations calculated + protected boolean covariancesCalculated = false; // = true when covariances and correlation coefficients calculated + + protected boolean nFactorOption = false; // = true varaiance, covariance and standard deviation denominator = n + // = false varaiance, covariance and standard deviation denominator = n-1 + + + // CONSTRUCTOR + public Scores(){ + } + + // TITLE + // Enter title (optional) + public void enterTitle(String title){ + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Title: " + title; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + else{ + this.title[0] = title; + } + } + + // MISSING RESPONSE + // Set percentage of no responses allowed within a person's responses before deletion of the person performed + public void setPersonDeletionPercentage(double perCent){ + this.personDeletionPercentage = perCent; + this.personDeletionPercentageSet = true; + if(this.itemDeletionPercentageSet && this.replacementOptionSet){ + this.allNoResponseOptionsSet = true; + if(this.dataEntered){ + this.preprocessData(); + } + } + } + + // Set percentage of no responses allowed within an item before deletion of the item performed + public void setItemDeletionPercentage(double perCent){ + this.itemDeletionPercentage = perCent; + this.itemDeletionPercentageSet = true; + if(this.personDeletionPercentageSet && this.replacementOptionSet){ + this.allNoResponseOptionsSet = true; + if(this.dataEntered){ + this.preprocessData(); + } + } + } + + // Set missing response option if deletion of item not carried out + // option = 1 - score replaced by zero + // option = 2 - score replaced by person's mean + // option = 3 - score replaced by item mean (default option) + // option = 4 - score replaced by overall mean + // option = 5 - user supplied score for each 'no response' + // requires data to be entered as a String matrix or from text file + // default option = 2 + public void setMissingDataOption(int option){ + if(option<1 || option>5)throw new IllegalArgumentException("The missing response option entered is " + option + "; the option must be 1, 2, 3, 4 or 5"); + this.replacementOption = option; + this.replacementOptionSet = true; + if(this.personDeletionPercentageSet && this.itemDeletionPercentageSet){ + this.allNoResponseOptionsSet = true; + if(this.dataEntered){ + this.preprocessData(); + } + } + } + + // Ignore requests for deletion percentages and replacement options + public void ignoreMissingDataOptionRequests(){ + this.ignoreNoResponseRequests = true; + this.allNoResponseOptionsSet = true; + this.itemDeletionPercentageSet = true; + this.personDeletionPercentageSet = true; + this.allNoResponseOptionsSet = true; + } + + + // Handling of 'no responses' + // Checks for and carries out item and/or person deletion + // checks for and carries out no response replacements + protected void noResponseHandling(){ + if(this.nNaN>0 && !this.noResponseHandlingSet){ + + // Check for person deletion + // Check whether any person has offered no responses at all + // If so - delete person irrespective of replacementOption choice + this.nDeletedPersons = 0; + + for(int j=0;j<this.nPersons; j++){ + int nIndNaN = 0; + this.deletedPersons[j] = false; + for(int i=0; i<this.nItems; i++){ + if(Double.isNaN(scores0[i][j])){ + nIndNaN++; + } + } + if(nIndNaN==this.nItems){ + this.deletedPersons[j] = true; + } + } + + for(int i=0; i<this.nPersons; i++){ + if(!this.deletedPersons[i]){ + int deletedSum = 0; + for(int j=0; j<this.nItems; j++){ + if(Double.isNaN(scores0[j][i])){ + deletedSum++; + double pc = (double)deletedSum*100.0/this.nItems; + if(pc>this.personDeletionPercentage){ + this.deletedPersons[i] = true; + } + } + } + } + } + + for(int i=0; i<this.nPersons; i++)if(this.deletedPersons[i])this.nDeletedPersons++; + if(this.nDeletedPersons>0){ + int counter = 0; + this.deletedPersonsIndices = new int[nDeletedPersons]; + for(int j=0;j<this.nPersons; j++){ + if(this.deletedPersons[j]){ + this.deletedPersonsIndices[counter] = j; + counter++; + } + } + double[][] scoreTemp = new double[this.nItems][this.nPersons - nDeletedPersons]; + this.personIndices = new int[this.nPersons - nDeletedPersons]; + counter = 0; + for(int i=0; i<this.nPersons; i++){ + if(!this.deletedPersons[i]){ + for(int j=0;j<this.nItems; j++){ + scoreTemp[j][counter] = this.scores0[j][i]; + } + this.personIndices[counter] = i; + counter++; + } + } + this.nPersons = this.nPersons - this.nDeletedPersons; + this.nScores = this.nPersons*this.nItems; + this.scores0 = scoreTemp; + } + if(this.nDeletedPersons==0){ + this.personIndices = new int[this.nPersons]; + for(int i=0; i<this.nPersons; i++)this.personIndices[i]=i; + } + + // Check for item deletion + // Check whether any item contains no responses at all + // If so - delete item irrespective of replacementOption choice + this.deletedItems = new boolean[this.nItems]; + this.nDeletedItems = 0; + for(int i=0;i<this.nItems; i++){ + int nItemNaN = 0; + deletedItems[i] = false; + for(int j=0; j<this.nPersons; j++){ + if(Double.isNaN(scores0[i][j]))nItemNaN++; + } + if(nItemNaN==this.nPersons){ + this.deletedItems[i] = true; + } + } + + for(int i=0; i<this.nItems; i++){ + this.deletedItems[i] = false; + int deletedSum = 0; + for(int j=0; j<this.nPersons; j++){ + if(Double.isNaN(scores0[i][j])){ + deletedSum++; + double pc = (double)deletedSum*100.0/this.nPersons; + if(pc>this.itemDeletionPercentage){ + this.deletedItems[i] = true; + } + } + } + } + for(int i=0; i<this.nItems; i++)if(this.deletedItems[i])this.nDeletedItems++; + + if(this.nDeletedItems>0){ + + int counter = 0; + this.deletedItemsIndices = new int[this.nDeletedItems]; + for(int i=0;i<this.nItems; i++){ + if(this.deletedItems[i]){ + this.deletedItemsIndices[counter] = i; + counter++; + } + } + + if(this.nItems-this.nDeletedItems<=1)throw new IllegalArgumentException("You have deleted " + nDeletedItems + " items leaving " + (this.nItems-this.nDeletedItems) + " items and hence no possibility calculation of alpha") ; + double[][] scoreTemp = new double[this.nItems-this.nDeletedItems][this.nPersons]; + String[] nameTemp = new String[this.nItems-this.nDeletedItems]; + this.itemIndices = new int[this.nItems-this.nDeletedItems]; + counter = 0; + for(int i=0; i<this.nItems; i++){ + if(!this.deletedItems[i]){ + nameTemp[counter] = this.itemNames[i]; + for(int j=0; j<this.nPersons; j++){ + scoreTemp[counter][j] = this.scores0[i][j]; + } + this.itemIndices[counter] = i; + counter++; + } + } + this.nItems = this.nItems - this.nDeletedItems; + this.nScores = this.nPersons*this.nItems; + this.scores0 = scoreTemp; + this.itemNames = nameTemp; + } + if(this.nDeletedItems==0){ + this.itemIndices = new int[this.nItems]; + for(int i=0; i<this.nItems; i++){ + this.itemIndices[i]=i; + } + } + + + // Number of remaining NaN + int newNaNn = 0; + for(int i=0; i<this.nPersons; i++){ + for(int j=0; j<this.nItems; j++){ + if(!Double.isNaN(scores0[j][i])){ + newNaNn++; + } + } + } + //Check for non-deleted 'no responses' and handle as dictated by replacementOption choice + if(newNaNn>0){ + // current item means and total means + double[] tItemMeans = new double[this.nItems]; + double tTotalMean = 0.0; + int counter2 = 0; + for(int i=0; i<this.nItems; i++){ + tItemMeans[i] = 0.0; + int counter = 0; + for(int j=0; j<this.nPersons; j++){ + if(!Double.isNaN(scores0[i][j])){ + tItemMeans[i] += scores0[i][j]; + counter++; + tTotalMean += scores0[i][j]; + counter2++; + } + } + tItemMeans[i] /= counter; + tTotalMean /= counter2; + } + + // current person means + double[] tIndivMeans = new double[this.nPersons]; + for(int i=0; i<this.nPersons; i++){ + tIndivMeans[i] = 0.0; + int counter = 0; + for(int j=0; j<this.nItems; j++){ + if(!Double.isNaN(scores0[j][i])){ + tIndivMeans[i] += scores0[j][i]; + counter++; + } + } + tIndivMeans[i] /= counter; + } + + + + // replacements + this.replacementIndices = new String[newNaNn]; + int rcounter = 0; + switch(replacementOption){ + case 1: // replace missing response by zero + for(int i=0; i<this.nItems; i++){ + for(int j=0; j<this.nPersons; j++){ + if(Double.isNaN(scores0[i][j])){ + scores0[i][j] = 0.0; + this.replacementIndices[rcounter] = this.itemNames[i] + ", " + (j+1) + ";"; + rcounter++; + } + } + } + break; + case 2: // replace missing response by mean of the person's responses + for(int i=0; i<this.nItems; i++){ + for(int j=0; j<this.nPersons; j++){ + if(Double.isNaN(scores0[i][j])){ + scores0[i][j] = tIndivMeans[i]; + this.replacementIndices[rcounter] = this.itemNames[i] + ", " + (j+1) + ";"; + rcounter++; + } + } + } + break; + case 3: // replace missing response by mean of the item + for(int i=0; i<this.nItems; i++){ + for(int j=0; j<this.nPersons; j++){ + if(Double.isNaN(scores0[i][j])){ + scores0[i][j] = tItemMeans[i]; + this.replacementIndices[rcounter] = this.itemNames[i] + ", " + (j+1) + ";"; + rcounter++; + } + } + } + break; + case 4: // replace missing response by mean of the total responses + for(int i=0; i<this.nItems; i++){ + for(int j=0; j<this.nPersons; j++){ + if(Double.isNaN(scores0[i][j])){ + scores0[i][j] = tTotalMean; + this.replacementIndices[rcounter] = this.itemNames[i] + ", " + (j+1) + ";"; + rcounter++; + } + } + } + break; + case 5: // replace missing response by user supplied value for each 'no resonse' occurence + for(int i=0; i<this.nItems; i++){ + for(int j=0; j<this.nPersons; j++){ + if(Double.isNaN(scores0[i][j])){ + String message1 = "Missing response:"; + String message2 = "\nItem index = " + i + ", item mean = " + Fmath.truncate(tItemMeans[i],4); + String message3 = "\nPerson index = " + j + ", person's responses mean = " + Fmath.truncate(tIndivMeans[j], 4) ; + String message4 = "\nTotal mean = " + Fmath.truncate(tTotalMean, 4) ; + String message5 = "\nEnter the replacement value" ; + String message = message1 + message2 + message3 + message4 + message5; + scores0[i][j] = Db.readDouble(message); + this.replacementIndices[rcounter] = this.itemNames[i] + ", " + (j+1) + ";"; + rcounter++; + } + } + } + break; + default: throw new IllegalArgumentException("!! It should not be possible to have an option choice (replacementOption) = " + replacementOption); + } + } + } + this.noResponseHandlingSet = true; + } + + // Check that all 'no response' options are set + protected void noResponseRequests(){ + + if(!this.allNoResponseOptionsSet){ + if(!this.ignoreNoResponseRequests){ + + // Options for no responses at a level that leads to item deletion + if(this.personDeletionPercentage!=0.0){ + if(!this.itemDeletionPercentageSet){ + String message0 = "There are missing responses in this data set"; + String message1 = "\nYou have not set the percentage of no responses at which you will delete an item"; + String message2 = "\n(0% = item deleted if a single 'no response' present in the item)"; + String message3 = "\n(100% = item never deleted)"; + String message4 = "\nEnter the required value and click OK "; + String message5 = "\nor simply click OK for default value"; + String message6 = message0 + message1 + message2 + message3 + message4 + message5; + this.itemDeletionPercentage = Db.readDouble(message6, this.itemDeletionPercentage); + } + } + this.itemDeletionPercentageSet = true; + + if(this.itemDeletionPercentage!=0.0){ + // Options for no responses at a level that leads to a person's deletion + if(!this.personDeletionPercentageSet){ + String message0 = "There are missing responses in this data set"; + String message1 = "\nYou have not set the percentage of no responses at which you will delete a person"; + String message2 = "\n(0% = person deleted if gives a single 'no response')"; + String message3 = "\n(100% = person never deleted)"; + String message4 = "\nEnter the required value and click OK "; + String message5 = "\nor simply click OK for default value"; + String message6 = message0 + message1 + message2 + message3 + message4 + message5; + this.personDeletionPercentage = Db.readDouble(message6, this.personDeletionPercentage); + } + } + this.personDeletionPercentageSet = true; + + if(this.itemDeletionPercentage!=0.0 && this.personDeletionPercentage!=0.0){ + // Options for no responses at a level that leads to a person's deletion + if(!this.replacementOptionSet){ + String message0 = "There are missing responses in this data set"; + String message1 = "\nYou have not set the option flag for replacing a missing score"; + String message2 = "\n option = 1 - score replaced by zero"; + String message3 = "\n option = 2 - score replaced by person's mean"; + String message4 = "\n option = 3 - score replaced by item mean (default option)"; + String message5 = "\n option = 4 - score replaced by overall mean"; + String message6 = "\n option = 5 - user supplied score for each 'no response'"; + String message7 = "\nEnter the required value and click OK "; + String message8 = "\nor simply click OK for default value"; + String message9 = message0 + message1 + message2 + message3 + message4 + message5 + message6 + message7 + message8; + this.replacementOption = Db.readInt(message9, this.replacementOption); + } + } + this.replacementOptionSet = true; + } + this.allNoResponseOptionsSet = true; + } + } + + // Set standard deviation, variance and covariance denominators to n + public void setDenominatorToN(){ + this.nFactorOption = true; + } + + // Set standard deviation, variance and covariance denominators to n + public void setDenominatorToNminusOne(){ + this.nFactorOption = false; + } + + // return indices of deleted persons + public int[] deletedPersonsIndices(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(this.nDeletedPersons==0){ + System.out.println("Method - deletedPersonsIndices: there are no deleted persons; null returned"); + return null; + } + else{ + ArrayMaths am1 = new ArrayMaths(this.deletedPersonsIndices); + ArrayMaths am2 = am1.plus(1); + return am2.array_as_int(); + } + } + + // return number of deleted persons + public int numberOfDeletedPersons(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.nDeletedPersons; + } + + // return indices of deleted items + public int[] deletedItemsIndices(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(this.nDeletedItems==0){ + System.out.println("Method - deletedItemsIndices: there are no deleted items; null returned"); + return null; + } + else{ + ArrayMaths am1 = new ArrayMaths(this.deletedItemsIndices); + ArrayMaths am2 = am1.plus(1); + return am2.array_as_int(); + } + } + + // return names of deleted items + public String[] deletedItemsNames(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(this.nDeletedItems==0){ + System.out.println("Method - deletedItemsIndices: there are no deleted items; null returned"); + return null; + } + else{ + String[] nam = new String[this.nDeletedItems]; + for(int i=0; i<this.nDeletedItems; i++){ + nam[i] = originalItemNames[this.deletedItemsIndices[i]]; + } + return nam; + } + } + + + // return number of deleted items + public int numberOfDeletedItems(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.nDeletedItems; + } + + + // ENTER SCORES + // 1. ENTER AS ROWS OF INDIVIDUAL SCORES FOR EACH ITEM + // Read scores from a text file as a matrix with rows of scores for each item + // File selected using a dialog window + // e.g. scores0[0][0] to scores0[0][nPersons-1] = scores for each person in turn for the first item + // scores0[1][0] to scores0[1][nPersons-1] = scores for each person in turn for the second item + // etc. + // scores may be represented by a number, yes, Yes, YES, no, No, NO, true, True, TRUE, false, False, FALSE or a letter(if a letter to numeral conversion as beeen set - see letterToNumeral()) + // 'no responses' may be represented by any one word text except those used to represent a response + public void readScoresAsRowPerItem(){ + //Select file + int lineNumber = 1; + FileChooser fin = new FileChooser("C:\\Java6\\Scores"); + + // Read in file name + this.inputFilename = fin.selectFile(); + if(fin.eol())lineNumber++; + + // Set title + this.title = new String[3]; + this.titleLines = 3; + this.title[0] = fin.readLine(); + this.title[1] = "Data read from file: " + this.inputFilename; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[2] = "Program execution initiated at " + tim + " on " + day; + + // Read in number of items + this.nItems = fin.readInt(); + if(fin.eol())lineNumber++; + + // Read in number of persons + this.nPersons = fin.readInt(); + if(fin.eol())lineNumber++; + this.nScores = this.nItems*this.nPersons; + + // Read in item names + this.itemNames = new String[this.nItems+1]; + for(int i=0; i<this.nItems; i++){ + this.itemNames[i] = fin.readWord(); + if(fin.eol())lineNumber++; + } + this.itemNames[this.nItems] = "total"; + this.originalItemNames = this.itemNames; + this.itemNamesSet = true; + + // Read in data to a String matrix + String[][] scores = new String[this.nItems][this.nPersons]; + for(int i=0; i<this.nItems; i++){ + int wordsPerLine = 1; + for(int j=0; j<this.nPersons; j++){ + scores[i][j] = fin.readWord(); + if(fin.eol()){ + if(wordsPerLine!=this.nPersons)throw new IllegalArgumentException("Line " + lineNumber + ": the number of scores in this row, " + wordsPerLine + ", does not equal the total number of persons, " + this.nPersons); + lineNumber++; + } + else{ + wordsPerLine++; + } + } + } + fin.close(); + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 1; + this.originalDataOrder = 0; + this.dataEntered = true; + } + + + // Read scores from a text file as a matrix with rows of scores for each item + // File name entered as argument + // e.g. scores0[0][0] to scores0[0][nPersons-1] = scores for each person in turn for the first item + // scores0[1][0] to scores0[1][nPersons-1] = scores for each person in turn for the second item + // etc. + // scores may be represented by a number, yes, Yes, YES, no, No, NO, true, True, TRUE, false, False, FALSE or a letter(if a letter to numeral conversion as beeen set - see letterToNumeral()) + // 'no responses' may be represented by any one word text except those used to represent a response + public void readScoresAsRowPerItem(String filename){ + + //Select file and read in data + int lineNumber = 1; + this.inputFilename = filename; + FileInput fin = new FileInput(filename); + if(fin.eol())lineNumber++; + + // Set title + this.title = new String[3]; + this.titleLines = 3; + this.title[0] = fin.readLine(); + this.title[1] = "Data read from file: " + filename; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[2] = "Program execution initiated at " + tim + " on " + day; + + // Read in number of items + this.nItems = fin.readInt(); + if(fin.eol())lineNumber++; + + // Read in number of persons + this.nPersons = fin.readInt(); + if(fin.eol())lineNumber++; + this.nScores = this.nItems*this.nPersons; + + // Read in item names + this.itemNames = new String[this.nItems+1]; + for(int i=0; i<this.nItems; i++){ + this.itemNames[i] = fin.readWord(); + if(fin.eol())lineNumber++; + + } + this.itemNames[this.nItems] = "total"; + this.originalItemNames = this.itemNames; + this.itemNamesSet = true; + + // Read in data to a String matrix + String[][] scores = new String[this.nItems][this.nPersons]; + for(int i=0; i<this.nPersons; i++){ + int wordsPerLine = 1; + for(int j=0; j<this.nItems; j++){ + scores[j][i] = fin.readWord(); + if(fin.eol()){ + if(wordsPerLine!=this.nItems)throw new IllegalArgumentException("Line " + lineNumber + ": the number of scores in this row, " + wordsPerLine + ", does not equal the total number of items, " + this.nItems); + lineNumber++; + } + else{ + wordsPerLine++; + } + + } + } + fin.close(); + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 1; + this.originalDataOrder = 0; + this.dataEntered = true; + } + + + // Enter scores as a matrix with rows of scores for each item - matrix of scores entered as String[][] + // e.g. scores0[0][0] to scores0[0][nPersons-1] = scores for each person in turn for the first item + // scores0[1][0] to scores0[1][nPersons-1] = scores for each person in turn for the second item + // etc. + // 'no responses' may be represented by any text except that that corresponds to a number + public void enterScoresAsRowPerItem(String[][] scores){ + + // Determine number of items, persons and scores + this.nItems = scores.length; + this.nPersons = scores[0].length; + this.nScores = this.nItems*this.nPersons; + + // Set title + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Untitled Scores Analysis"; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 1; + this.originalDataOrder = 0; + this.dataEntered = true; + } + + + // Enter scores as a matrix with rows of scores for each item - matrix of scores entered as double[][] + // e.g. scores0[0][0] to scores0[0][nPersons-1] = scores for each person in turn for the first item + // scores0[1][0] to scores0[1][nPersons-1] = scores for each person in turn for the second item + // etc. + // 'no responses' must be represenred by Double.NaN + public void enterScoresAsRowPerItem(double[][] scores){ + + // Determine number of items, persons and scores + this.nItems = scores.length; + this.nPersons = scores[0].length; + this.nScores = this.nItems*this.nPersons; + + // Set title + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Untitled"; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 2; + this.originalDataOrder = 0; + this.dataEntered = true; + } + + + // Enter scores as a matrix with rows of scores for each item - matrix of scores entered as Matrix + // e.g. scores0[0][0] to scores0[0][nPersons-1] = scores for each person in turn for the first item + // scores0[1][0] to scores0[1][nPersons-1] = scores for each person in turn for the second item + // etc. + // 'no responses' must be represented by Double.NaN + public void enterScoresAsRowPerItem(Matrix scores){ + double[][] scoresdd = scores.getArrayCopy(); + + // Determine number of items, persons and scores + this.nItems = scoresdd.length; + this.nPersons = scoresdd[0].length; + this.nScores = this.nItems*this.nPersons; + + // Set title + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Untitled Scores Analysis"; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 3; + this.originalDataOrder = 0; + this.dataEntered = true; + } + + + + // Enter scores as a matrix with rows of scores for each item - matrix of scores entered as float[][] + // e.g. scores0[0][0] to scores0[0][nPersons-1] = scores for each person in turn for the first item + // scores0[1][0] to scores0[1][nPersons-1] = scores for each person in turn for the second item + // etc. + // 'no responses' must be represenred by Float.NaN + public void enterScoresAsRowPerItem(float[][] scores){ + + // Determine number of items, persons and scores + this.nItems = scores.length; + this.nPersons = scores[0].length; + this.nScores = this.nItems*this.nPersons; + + // Set title + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Untitled Scores Analysis"; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 4; + this.originalDataOrder = 0; + this.dataEntered = true; + } + + + // Enter scores as a matrix with rows of scores for each item - matrix of scores entered as int[][] + // e.g. scores0[0][0] to scores0[0][nPersons-1] = scores for each person in turn for the first item + // scores0[1][0] to scores0[1][nPersons-1] = scores for each person in turn for the second item + // etc. + // 'no responses' cannot be entered - see above for methods, e.g. matrix entered as String[][] or double[][], that allow no responses to be entered + public void enterScoresAsRowPerItem(int[][] scores){ + + // Determine number of items, persons and scores + this.nItems = scores.length; + this.nPersons = scores[0].length; + this.nScores = this.nItems*this.nPersons; + + // Set title + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Untitled Scores Analysis"; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 5; + this.originalDataOrder = 0; + this.dataEntered = true; + } + + // Enter scores as a matrix with rows of scores for each item - matrix of scores entered as char[][] + // e.g. scores0[0][0] to scores0[0][nPersons-1] = scores for each person in turn for the first item + // scores0[1][0] to scores0[1][nPersons-1] = scores for each person in turn for the second item + // etc. + // responses may be represented by a numeral (0 to 9), y, Y, n, N or a letter(if letter input as been set - see letterToNumeral()) + // 'no responses' may be represented by any character except those used to indicate a response + public void enterScoresAsRowPerItem(char[][] scores){ + + // Determine number of items, persons and scores + this.nItems = scores.length; + this.nPersons = scores[0].length; + this.nScores = this.nItems*this.nPersons; + + // Set title + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Untitled Scores Analysis"; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 6; + this.originalDataOrder = 0; + this.dataEntered = true; + } + + + // Enter scores as a matrix with rows of scores for each item - scores either true or false - matrix of scores entered as boolean[][] + // e.g. scores0[0][0] to scores0[0][nPersons-1] = scores for each person in turn for the first item + // scores0[1][0] to scores0[1][nPersons-1] = scores for each person in turn for the second item + // etc. + // 'no responses' cannot be entered - see above for methods, e.g. matrix entered as String[][] or double[][], that allow no responses to be entered + public void enterScoresAsRowPerItem(boolean[][] scores){ + + // Determine number of items, persons and scores + this.nItems = scores.length; + this.nPersons = scores[0].length; + this.nScores = this.nItems*this.nPersons; + this.dichotomous = new boolean[this.nItems]; + this.dichotomousPercentage = new double[this.nItems]; + for(int i=0; i<this.nItems; i++){ + this.dichotomous[i]=true; + this.dichotomousPercentage[i]=100.0; + } + this.dichotomousOverall = true; + this.dichotomousCheckDone = true; + + // Set title + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Untitled Scores Analysis"; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 7; + this.originalDataOrder = 0; + this.dataEntered = true; + } + + + // 2. ENTER AS ROWS OF SCORES FOR EACH PERSON + // Read scores from a text file as a matrix with rows of scores for each person + // File selected using a dialog window + // e.g. scores1[0][0] to scores1[0][nItems-1] = scores for each item in turn for the first person + // scores1[1][0] to scores1[1][nItems-1] = scores for each item in turn for the second person + // etc. + // scores may be represented by a number, yes, Yes, YES, no, No, NO, true, True, TRUE, false, False, FALSE or a letter(if a letter to numeral conversion as beeen set - see letterToNumeral()) + // 'no responses' may be represented by any one word text except those used to represent a response + public void readScoresAsRowPerPerson(){ + //Select file + int lineNumber = 1; + FileChooser fin = new FileChooser("C:\\Java6\\Scores"); + + // Read in file name + this.inputFilename = fin.selectFile(); + if(fin.eol())lineNumber++; + + // Set title + this.title = new String[3]; + this.titleLines = 3; + this.title[0] = "Title: " + fin.readLine(); + this.title[1] = "Data read from file: " + this.inputFilename; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[2] = "Program execution initiated at " + tim + " on " + day; + + // Read in number of items + this.nItems = fin.readInt(); + if(fin.eol())lineNumber++; + + // Read in number of persons + this.nPersons = fin.readInt(); + if(fin.eol())lineNumber++; + this.nScores = this.nItems*this.nPersons; + + // Read in item names + this.itemNames = new String[this.nItems+1]; + for(int i=0; i<this.nItems; i++){ + this.itemNames[i] = fin.readWord(); + if(fin.eol())lineNumber++; + } + this.itemNames[this.nItems] = "total"; + this.originalItemNames = this.itemNames; + this.itemNamesSet = true; + + // Read in data to a String matrix + String[][] scores = new String[this.nPersons][this.nItems]; + for(int i=0; i<this.nPersons; i++){ + int wordsPerLine = 1; + for(int j=0; j<this.nItems; j++){ + scores[i][j] = fin.readWord(); + if(fin.eol()){ + if(wordsPerLine!=this.nItems)throw new IllegalArgumentException("Line " + lineNumber + ": the number of scores in this row, " + wordsPerLine + ", does not equal the total number of items, " + this.nItems); + lineNumber++; + } + else{ + wordsPerLine++; + } + } + } + fin.close(); + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 1; + this.originalDataOrder = 1; + this.dataEntered = true; + } + + + // Read scores from a text file as a matrix with rows of scores for each person + // File name entered as argument + // e.g. scores1[0][0] to scores1[0][nItems-1] = scores for each item in turn for the first person + // scores1[1][0] to scores1[1][nItems-1] = scores for each item in turn for the second person + // etc. + // scores may be represented by a number, yes, Yes, YES, no, No, NO, true, True, TRUE, false, False, FALSE or a letter(if a letter to numeral conversion as beeen set - see letterToNumeral()) + // 'no responses' may be represented by any one word text except those used to represent a response + public void readScoresAsRowPerPerson(String filename){ + + //Select file and read in data + int lineNumber = 1; + this.inputFilename = filename; + FileInput fin = new FileInput(filename); + if(fin.eol())lineNumber++; + + // Set title + this.title = new String[3]; + this.titleLines = 3; + this.title[0] = "Title: " + fin.readLine(); + this.title[1] = "Data read from file: " + filename; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[2] = "Program execution initiated at " + tim + " on " + day; + + // Read in number of items + this.nItems = fin.readInt(); + if(fin.eol())lineNumber++; + + // Read in number of persons + this.nPersons = fin.readInt(); + if(fin.eol())lineNumber++; + this.nScores = this.nItems*this.nPersons; + + // Read in item names + this.itemNames = new String[this.nItems+1]; + for(int i=0; i<this.nItems; i++){ + this.itemNames[i] = fin.readWord(); + if(fin.eol())lineNumber++; + } + this.itemNames[this.nItems] = "total"; + this.originalItemNames = this.itemNames; + this.itemNamesSet = true; + + // Read in data to a String matrix + String[][] scores = new String[this.nPersons][this.nItems]; + for(int i=0; i<this.nPersons; i++){ + int wordsPerLine = 1; + for(int j=0; j<this.nItems; j++){ + scores[i][j] = fin.readWord(); + if(fin.eol()){ + if(wordsPerLine!=this.nItems)throw new IllegalArgumentException("Line " + lineNumber + ": the number of scores in this row, " + wordsPerLine + ", does not equal the total number of items, " + this.nItems); + lineNumber++; + } + else{ + wordsPerLine++; + } + + } + } + fin.close(); + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 1; + this.originalDataOrder = 1; + this.dataEntered = true; + } + + + // Enter scores as a matrix with rows of scores for each person - matrix of scores entered as String[][] + // e.g. scores1[0][0] to scores1[0][nItems-1] = scores for each item in turn for the first person + // scores1[1][0] to scores1[1][nItems-1] = scores for each item in turn for the second person + // etc. + // scores may be represented by a number, yes, Yes, YES, no, No, NO, true, True, TRUE, false, False or FALSE + // 'no responses' may be represented by any one word text except that that corresponds to a number, yes, Yes, YES, no, No, NO, true, True, TRUE, false, False or FALSE + public void enterScoresAsRowPerIperson(String[][] scores){ + + // Determine number of items, persons and scores + this.nPersons = scores.length; + this.nItems = scores[0].length; + this.nScores = this.nItems*this.nPersons; + + // Set title + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Untitled Scores Analysis"; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 2; + this.originalDataOrder = 1; + this.dataEntered = true; + } + + + // Enter scores as a matrix with rows of scores for each person - matrix of scores entered as double[][] + // e.g. scores1[0][0] to scores1[0][nItems-1] = scores for each item in turn for the first person + // scores1[1][0] to scores1[1][nItems-1] = scores for each item in turn for the second person + // etc. + // 'no responses' must be represenred by Double.NaN + public void enterScoresAsRowPerPerson(double[][] scores){ + + // Determine number of items, persons and scores + this.nPersons = scores.length; + this.nItems = scores[0].length; + this.nScores = this.nItems*this.nPersons; + + // Set title + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Untitled Scores Analysis"; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 2; + this.originalDataOrder = 1; + this.dataEntered = true; + } + + + // Enter scores as a matrix with rows of scores for each iperson - matrix of scores entered as Matrix + // e.g. scores1[0][0] to scores1[0][nItems-1] = scores for each item in turn for the first person + // scores1[1][0] to scores1[1][nItems-1] = scores for each item in turn for the second person + // etc. + // 'no responses' must be represenred by Double.NaN + public void enterScoresAsRowPerPerson(Matrix scores){ + double[][] scoresdd = scores.getArrayCopy(); + + // Determine number of items, persons and scores + this.nPersons = scoresdd.length; + this.nItems = scoresdd[0].length; + this.nScores = this.nItems*this.nPersons; + + // Set title + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Untitled Scores Analysis"; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 3; + this.originalDataOrder = 1; + this.dataEntered = true; + } + + // Enter scores as a matrix with rows of scores for each person - matrix of scores entered as float[][] + // e.g. scores1[0][0] to scores1[0][nItems-1] = scores for each item in turn for the first person + // scores1[1][0] to scores1[1][nItems-1] = scores for each item in turn for the second person + // etc. + // 'no responses' must be represenred by Float.NaN + public void enterScoresAsRowPerPerson(float[][] scores){ + + // Determine number of items, persons and scores + this.nPersons = scores.length; + this.nItems = scores[0].length; + this.nScores = this.nItems*this.nPersons; + + // Set title + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Untitled Scores Analysis"; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 4; + this.originalDataOrder = 1; + this.dataEntered = true; + } + + + // Enter scores as a matrix with rows of scores for each person - matrix of scores entered as int[][] + // e.g. scores1[0][0] to scores1[0][nItems-1] = scores for each item in turn for the first person + // scores1[1][0] to scores1[1][nItems-1] = scores for each item in turn for the second person + // etc. + // 'no responses' cannot be entered - see above for methods, e.g. matrix entered as String[][] or double[][], that allow no responses to be entered + public void enterScoresAsRowPerPerson(int[][] scores){ + + // Determine number of items, persons and scores + this.nPersons = scores.length; + this.nItems = scores[0].length; + this.nScores = this.nItems*this.nPersons; + + // Set title + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Untitled Scores Analysis"; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 5; + this.originalDataOrder = 1; + this.dataEntered = true; + } + + + // Enter scores as a matrix with rows of scores for each person - matrix of scores entered as char[][] + // e.g. scores1[0][0] to scores1[0][nItems-1] = scores for each item in turn for the first person + // scores1[1][0] to scores1[1][nItems-1] = scores for each item in turn for the second person + // etc. + // responses may be represented by a numeral (0 to 9), y, Y, n, N or a letter(if letter input as been set - see letterToNumeral()) + // 'no responses' may be represented by any character except those used to indicate a response + public void enterScoresAsRowPerPerson(char[][] scores){ + + // Determine number of items, persons and scores + this.nPersons = scores.length; + this.nItems = scores[0].length; + this.nScores = this.nItems*this.nPersons; + + // Set title + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Untitled Scores Analysis"; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 6; + this.originalDataOrder = 1; + this.dataEntered = true; + } + + + // Enter scores as a matrix with rows of scores for each person - scores either true or false - matrix of scores entered as boolean[][] + // e.g. scores1[0][0] to scores1[0][nItems-1] = scores for each item in turn for the first person + // scores1[1][0] to scores1[1][nItems-1] = scores for each item in turn for the second person + // etc. + // 'no responses' cannot be entered - see above for methods, e.g. matrix entered as String[][] or double[][], that allow no responses to be entered + public void enterScoresAsRowPerPerson(boolean[][] scores){ + + // Determine number of items, persons and scores + this.nPersons = scores.length; + this.nItems = scores[0].length; + this.nScores = this.nItems*this.nPersons; + this.dichotomous = new boolean[this.nItems]; + this.dichotomousPercentage = new double[this.nItems]; + for(int i=0; i<this.nItems; i++){ + this.dichotomous[i]=true; + this.dichotomousPercentage[i]=100.0; + } + this.dichotomousOverall = true; + this.dichotomousCheckDone = true; + + // Set title + if(this.title==null){ + this.title = new String[2]; + this.title[0] = "Untitled Scores Analysis"; + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + this.title[1] = "Program execution initiated at " + tim + " on " + day; + } + + // Store entered data + this.originalData = (Object)scores; + this.originalDataType = 7; + this.originalDataOrder = 1; + this.dataEntered = true; + } + + // Enter item names, i.e. one word item titles + // default values are item1, item2, item3 etc. + public void enterItemNames(String[] itemNames){ + int len = itemNames.length; + this.itemNames = new String[len+1]; + for(int i=0; i<len; i++)this.itemNames[i] = itemNames[i]; + this.itemNames[len]="total"; + this.itemNamesSet = true; + } + + // Allow alphabetic responses, i.e. A, B, C, to be converted to numerical responses, i.e. 1, 2, 3, 4 + // A, B, C, to be converted to numerical responses, e.g. 1, 2, 3, 4 + public void letterToNumeral(){ + this.letterToNumeralSet = true; + } + + // Allow other dichotomous data pairs than the default pairs, + // i.e. other than a numeral, (true, True, TRUE; false, Flase, FALSE), (Y, y, yes, Yes, YES; N, n, no, No, NO) + public void otherDichotomousData(String falseSign, String trueSign){ + this.otherFalse = falseSign; + this.otherTrue = trueSign; + this.otherDichotomousDataSet = true; + } + + + // SCORE MATRIX TRANSPOSTIONS + // Transpose scores0 to scores1 - double[][] + protected double[][] transpose0to1(double[][]scores00){ + int n0 = scores00.length; + int n1 = scores00[0].length; + double[][] scores11 = new double[n1][n0]; + for(int i=0; i<n0; i++){ + for(int j=0; j<n1; j++){ + scores11[j][i] = scores00[i][j]; + } + } + return scores11; + } + + // Transpose scores0 to scores1 - String[][] + protected String[][] transpose0to1(String[][]scores00){ + int n0 = scores00.length; + int n1 = scores00[0].length; + String[][] scores11 = new String[n1][n0]; + for(int i=0; i<n0; i++){ + for(int j=0; j<n1; j++){ + scores11[j][i] = scores00[i][j]; + } + } + return scores11; + } + + // Transpose scores1 to scores0 - double[][] + protected double[][] transpose1to0(double[][]scores11){ + int n0 = scores11.length; + int n1 = scores11[0].length; + double[][] scores00 = new double[n1][n0]; + for(int i=0; i<n0; i++){ + for(int j=0; j<n1; j++){ + scores00[j][i] = scores11[i][j]; + } + } + return scores00; + } + + // Transpose scores1 to scores0 - String[][] + protected String[][] transpose1to0(String[][]scores11){ + int n0 = scores11.length; + int n1 = scores11[0].length; + String[][] scores00 = new String[n1][n0]; + for(int i=0; i<n0; i++){ + for(int j=0; j<n1; j++){ + scores00[j][i] = scores11[i][j]; + } + } + return scores00; + } + + // Transpose scores1 to scores0 - boolean[][] + protected boolean[][] transpose1to0(boolean[][]scores11){ + int n0 = scores11.length; + int n1 = scores11[0].length; + boolean[][] scores00 = new boolean[n1][n0]; + for(int i=0; i<n0; i++){ + for(int j=0; j<n1; j++){ + scores00[j][i] = scores11[i][j]; + } + } + return scores00; + } + + + // CHECK FOR LENGTH CONSISTENCY IN ENTERED SCORES + + // check lengths of String[][] + protected void checkLengths(String[][] scores){ + int n0 = scores.length; + int n1 = scores[0].length; + for(int i=1; i<n0; i++){ + if(scores[i].length!=n1){ + throw new IllegalArgumentException("The length of each item and of each person's responses must be identical (missing responses must be included - see documentation web page)"); + } + } + } + + // check lengths of double[][] + protected void checkLengths(double[][] scores){ + int n0 = scores.length; + int n1 = scores[0].length; + for(int i=1; i<n0; i++){ + if(scores[i].length!=n1){ + throw new IllegalArgumentException("The length of each item and of each person's responses must be identical (missing responses must be included - see documentation web page)"); + } + } + } + + // check lengths of char[][] + protected void checkLengths(char[][] scores){ + int n0 = scores.length; + int n1 = scores[0].length; + for(int i=1; i<n0; i++){ + if(scores[i].length!=n1){ + throw new IllegalArgumentException("The length of each item and of each person's responses must be identical (missing responses must be included - see documentation web page)"); + } + } + } + + // check lengths of float[][] + protected void checkLengths(float[][] scores){ + int n0 = scores.length; + int n1 = scores[0].length; + for(int i=1; i<n0; i++){ + if(scores[i].length!=n1){ + throw new IllegalArgumentException("The length of each item and of each person's responses must be identical (missing responses must be included - see documentation web page)"); + } + } + } + + // check lengths of int[][] + protected void checkLengths(int[][] scores){ + int n0 = scores.length; + int n1 = scores[0].length; + for(int i=1; i<n0; i++){ + if(scores[i].length!=n1){ + throw new IllegalArgumentException("The length of each item and of each person's responses must be identical (missing responses must be included - see documentation web page)"); + } + } + } + + // check lengths of boolean[][] + protected void checkLengths(boolean[][] scores){ + int n0 = scores.length; + int n1 = scores[0].length; + for(int i=1; i<n0; i++){ + if(scores[i].length!=n1){ + throw new IllegalArgumentException("The length of each item and of each person's responses must be identical (missing responses must be included - see documentation web page)"); + } + } + } + + + // TRIM SCORES ELEMENTS + // Trim all elements of leading and trailing spaces + protected void trimScores(String[][] scores){ + int n = scores.length; + int m = scores[0].length; + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + scores[i][j].trim(); + } + } + } + + + // PREPROCESS DATA + // Delete persons and items if required + // Make substititions for any non-deleted 'no responses' + // Assign data to scores1 array and orginal scores array + // Calculate standardized data + // Call calculation of means, sums and variances + protected void preprocessData(){ + + if(!this.dataPreprocessed){ + if(!this.dataEntered)throw new IllegalArgumentException("No data has been entered"); + + // Array initialization + this.scores0 = new double[this.nItems][this.nPersons]; + this.originalScores0 = new double[this.nItems][this.nPersons]; + this.scores1 = new double[this.nPersons][this.nItems]; + this.originalScores1 = new double[this.nPersons][this.nItems]; + this.deletedPersons = new boolean[this.nPersons]; + this.deletedItems = new boolean[this.nItems]; + this.personIndices = new int[this.nPersons]; + for(int i=0; i<this.nPersons; i++)this.personIndices[i] = i; + this.itemIndices = new int[this.nItems]; + for(int i=0; i<this.nItems; i++)this.itemIndices[i] = i; + + + // instance variable initialization + this.nNaN = 0; + this.nDeletedPersons = 0; + this.nDeletedItems = 0; + + // Title names + if(this.itemNamesSet){ + if((this.nItems+1)!=this.itemNames.length)throw new IllegalArgumentException("The number of item names, " + this.itemNames.length + ", does not equal the number of items, " + this.nItems); + } + else{ + this.itemNames = new String[this.nItems+1]; + for(int i=0; i<this.nItems; i++)this.itemNames[i] = "item" + i; + this.itemNames[this.nItems] = "total"; + } + + // Recover entered data as String, double or boolean arrays and transpose entered scores1 format to scores0 format + String[][] holdingArrayS = null; + double[][] holdingArrayD = null; + boolean[][] holdingArrayB = null; + int m = 0; + int n = 0; + switch(this.originalDataType){ + case 1: holdingArrayS = (String[][])originalData; + this.checkLengths(holdingArrayS); + // transpose to scores0 format + if(this.originalDataOrder==1){ + holdingArrayS = this.transpose1to0(holdingArrayS); + } + this.trimScores(holdingArrayS); + break; + case 2: holdingArrayD = (double[][])originalData; + this.checkLengths(holdingArrayD); + // transpose to scores0 format + if(this.originalDataOrder==1){ + holdingArrayD = this.transpose1to0(holdingArrayD); + } + break; + case 3: holdingArrayD = ((Matrix)originalData).getArrayCopy(); + this.checkLengths(holdingArrayD); + // transpose to scores0 format + if(this.originalDataOrder==1){ + holdingArrayD = this.transpose1to0(holdingArrayD); + } + break; + case 4: float[][] holdingArrayF = (float[][])originalData; + this.checkLengths(holdingArrayF); + // convert to double[][] + m = holdingArrayF.length; + n = holdingArrayF[0].length; + for(int i=0; i<m; i++){ + for(int j=0; j<n; j++){ + holdingArrayD[i][j] = (new Float(holdingArrayF[i][j])).doubleValue(); + } + } + // transpose to scores0 format + if(this.originalDataOrder==1){ + holdingArrayD = this.transpose1to0(holdingArrayD); + } + break; + case 5: int[][] holdingArrayI = (int[][])originalData; + this.checkLengths(holdingArrayI); + // convert to double[][] + m = holdingArrayI.length; + n = holdingArrayI[0].length; + for(int i=0; i<m; i++){ + for(int j=0; j<n; j++){ + holdingArrayD[i][j] = (new Integer(holdingArrayI[i][j])).doubleValue(); + } + } + // transpose to scores0 format + if(this.originalDataOrder==1){ + holdingArrayD = this.transpose1to0(holdingArrayD); + } + break; + case 6: char[][] holdingArrayC = (char[][])originalData; + this.checkLengths(holdingArrayC); + // convert to String[][] + m = holdingArrayC.length; + n = holdingArrayC[0].length; + holdingArrayS = new String[m][n]; + for(int i=0; i<m; i++){ + for(int j=0; j<n; j++){ + holdingArrayS[i][j] = Character.toString(holdingArrayC[i][j]); + } + } + // transpose to scores0 format + if(this.originalDataOrder==1){ + holdingArrayS = this.transpose1to0(holdingArrayS); + } + this.trimScores(holdingArrayS); + break; + case 7: holdingArrayB = (boolean[][])originalData; + this.checkLengths(holdingArrayB); + // transpose to scores0 format + if(this.originalDataOrder==1){ + holdingArrayB = this.transpose1to0(holdingArrayB); + } + break; + } + + + // Identify 'no responses' (->NaN)and convert all to double[][] + switch(this.originalDataType){ + case 1: + case 6: for(int i=0; i<this.nItems; i++){ + for(int j=0; j<this.nPersons; j++){ + boolean elementSet = false; + if(this.otherDichotomousDataSet){ + if(holdingArrayS[i][j].equalsIgnoreCase(this.otherTrue)){ + this.scores0[i][j]=1; + elementSet = true; + } + else{ + if(holdingArrayS[i][j].equalsIgnoreCase(this.otherFalse)){ + this.scores0[i][j]=0; + elementSet = true; + } + else{ + this.scores0[i][j] = Double.NaN; + elementSet = true; + } + } + } + if(!elementSet){ + if(this.letterToNumeralSet){ + char elem = holdingArrayS[i][j].charAt(0); + if((int)elem>64 && elem<91 && holdingArrayS[i][j].length()==1){ + this.scores0[i][j] = elem - 63; + elementSet = true; + } + else{ + if((int)elem>96 && elem<123 && holdingArrayS[i][j].length()==1){ + this.scores0[i][j] = elem - 96; + elementSet = true; + } + else{ + this.scores0[i][j] = Double.NaN; + elementSet = true; + } + } + } + } + if(!elementSet){ + if(holdingArrayS[i][j].equalsIgnoreCase("yes") || holdingArrayS[i][j].equalsIgnoreCase("y") || holdingArrayS[i][j].equalsIgnoreCase("true")){ + this.scores0[i][j]=1; + elementSet = true; + } + else{ + if(holdingArrayS[i][j].equalsIgnoreCase("no") || holdingArrayS[i][j].equalsIgnoreCase("n") || holdingArrayS[i][j].equalsIgnoreCase("false")){ + this.scores0[i][j]=0; + elementSet = true; + } + } + } + if(!elementSet){ + try{ + this.scores0[i][j] = Double.valueOf(holdingArrayS[i][j]); + } + catch (Exception e){ + this.scores0[i][j] = Double.NaN; + this.nNaN++; + } + } + } + } + break; + case 2: + case 3: + case 4: + case 5: for(int i=0; i<this.nItems; i++){ + for(int j=0; j<this.nPersons; j++){ + try{ + this.scores0[i][j] = Double.valueOf(holdingArrayD[i][j]); + } + catch (Exception e){ + this.scores0[i][j] = Double.NaN; + this.nNaN++; + } + } + } + break; + case 7: for(int i=0; i<this.nItems; i++){ + for(int j=0; j<this.nPersons; j++){ + if(holdingArrayB[i][j]){ + this.scores0[i][j] = 1.0; + } + else{ + this.scores0[i][j] = 0.0; + } + } + } + break; + } + + + + // assign original scores to instance variable + this.originalScores0 = scores0.clone(); + this.originalScores1 = this.transpose0to1(scores0); + this.originalNitems = this.nItems; + this.originalNpersons = this.nPersons; + this.originalNscores = this.originalNitems*this.originalNpersons; + + // Handle no responses + // Check for and carry out item deletion + // check for and carry out no response replacement + if(this.nNaN>0)this.noResponseHandling(); + + // Create row - column transposed matrix + this.scores1 = new double[this.nPersons][this.nItems]; + for(int i=0; i<this.nItems; i++){ + for(int j=0; j<this.nPersons; j++){ + this.scores1[j][i] = this.scores0[i][j]; + } + } + + // Check which original raw data items are dichotomous + this.checkWhetherRawItemsDichotomous(); + + // Standardize data in all items + this.standardizedScores0 = new double[this.nItems][this.nPersons]; + this.standardizedScores1 = new double[this.nPersons][this.nItems]; + for(int i=0; i<this.nItems; i++){ + Stat st = new Stat(this.scores0[i]); + this.standardizedScores0[i] = st.standardize(); + } + this.standardizedScores1 = this.transpose0to1(this.standardizedScores0); + + // Calculate means, standard deviations and variances of all items and all persons sets + this.meansAndVariances(); + + // Calculate covariances and correlation coefficients + this.covariancesAndCorrelationCoefficients(); + + this.dataPreprocessed = true; + } + } + + + // RETURN RESPONSES + // Return responses as entered + public Object originalResponses(){ + return originalScores(); + } + + public Object originalScores(){ + if(!this.dataEntered)throw new IllegalArgumentException("No data has been entered"); + return this.originalData; + } + + // Return original data as rows per person + public double[][] originalResponsesAsRowPerPerson(){ + return originalScoresAsRowPerPerson(); + } + + public double[][] originalScoresAsRowPerPerson(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.originalScores1; + } + + // Return original data as rows per item + public double[][] originalResponsesAsRowPerItem(){ + return originalScoresAsRowPerItem(); + } + + public double[][] originalScoresAsRowPerItem(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.originalScores0; + } + + // Return used data as rows per person, i.e. data after any deletions + public double[][] usedresponsesAsRowPerPerson(){ + return usedScoresAsRowPerPerson(); + } + + public double[][] usedScoresAsRowPerPerson(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.scores1; + } + + // Return used data as rows per item, i.e. data after any deletions + public double[][] usedScoresAsRowPerItem(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.scores0; + } + + // Return standardized data as rows per person + public double[][] standardizedScoresAsRowPerPerson(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.standardizedScores1; + } + + public double[][] standardisedScoresAsRowPerPerson(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.standardizedScores1; + } + + // Return standardized data as rows per item + public double[][] standardizedScoresAsRowPerItem(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.standardizedScores0; + } + + public double[][] standardisedScoresAsRowPerItem(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.standardizedScores0; + } + + // Return original number of items + public int originalNumberOfItems(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.originalNitems; + } + + // Return original number of persons + public int originalNumberOfPersons(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.originalNpersons; + } + + // Return used number of items, i.e. after any deletions + public int usedNumberOfItems(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.nItems; + } + + // Return used number of persons, i.e. after any deletions + public int usedNumberOfPersons(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.nPersons; + } + + + // Return original total number of responses + public int originalTotalNumberOfScores(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.originalNscores; + } + + // Return original total number of responses, i.e. after any deletions + public int usedTotalNumberOfScores(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.nScores; + } + + // Return number of responses deleted + public int numberOfDeletedScores(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.originalNscores - this.nScores; + } + + // Return number of responses replaced + public int numberOfReplacedScores(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.nReplacements; + } + + // Return item name and person index of all replaced responses + public String[] indicesOfReplacedScores(){ + if(!this.dataPreprocessed)this.preprocessData(); + return this.replacementIndices; + } + + // Get item names + public String[] itemNames(){ + if(!this.dataEntered)throw new IllegalArgumentException("no data has been entered"); + String[] ret = new String[this.nItems]; + for(int i=0; i<this.nItems; i++)ret[i] = this.itemNames[i]; + return ret; + } + + public String[] originalItemNames(){ + if(!this.dataEntered)throw new IllegalArgumentException("no data has been entered"); + String[] ret = new String[this.originalNitems]; + for(int i=0; i<this.originalNitems; i++)ret[i] = this.originalItemNames[i]; + return ret; + } + + + // Get index for a given item name + public int itemIndex(String itemName){ + if(!this.dataEntered)throw new IllegalArgumentException("no data has been entered"); + int index = -1; + int jj=0; + boolean test = true; + while(test){ + if(itemName.trim().equalsIgnoreCase(this.itemNames[jj].trim())){ + index = jj; + test = false; + } + else{ + jj++; + if(jj>this.nItems)throw new IllegalArgumentException("Item name, " + itemName + ", is not present in the list of entered item names"); + } + } + return index+1; + } + + // Get item name for a given index + public String itemName(int index){ + if(!this.dataEntered)throw new IllegalArgumentException("no data has been entered"); + return this.itemNames[index-1]; + } + + + // SUMS, MEANS, VARIANCES, STANDARD DEVIATION, MEDIANS, MAXIMA AND MINIMA + // Calculate item and person sums, means, variances, standard deviations, mimima and maxima + // plus same for total responses + protected void meansAndVariances(){ + + // ITEMS + this.rawItemMeans = new double[this.nItems]; + this.rawItemMedians = new double[this.nItems]; + this.rawItemStandardDeviations = new double[this.nItems]; + this.rawItemVariances = new double[this.nItems]; + this.rawItemMinima = new double[this.nItems]; + this.rawItemMaxima = new double[this.nItems]; + this.rawItemRanges = new double[this.nItems]; + this.rawItemTotals = new double[this.nItems]; + this.rawItemMomentSkewness = new double[this.nItems]; + this.rawItemMedianSkewness = new double[this.nItems]; + this.rawItemQuartileSkewness = new double[this.nItems]; + this.rawItemKurtosisExcess = new double[this.nItems]; + + for(int i=0; i<this.nItems; i++){ + Stat am0 = new Stat(this.scores0[i]); + if(this.nFactorOption){ + am0.setDenominatorToN(); + } + else{ + am0.setDenominatorToNminusOne(); + } + + this.rawItemMeans[i] = am0.mean_as_double(); + this.rawItemVariances[i] = am0.variance_as_double(); + this.rawItemStandardDeviations[i] = Math.sqrt(this.rawItemVariances[i]); + this.rawItemMinima[i] = am0.minimum_as_double(); + this.rawItemMaxima[i] = am0.maximum_as_double(); + this.rawItemRanges[i] = this.rawItemMaxima[i] - this.rawItemMinima[i]; + this.rawItemTotals[i] = am0.sum_as_double(); + Stat ams0 = am0.sort(); + this.rawItemMedians[i] = ams0.median_as_double(); + this.rawItemMomentSkewness[i] = am0.momentSkewness_as_double(); + this.rawItemMedianSkewness[i] = am0.medianSkewness_as_double(); + this.rawItemQuartileSkewness[i] = am0.quartileSkewness_as_double(); + this.rawItemKurtosisExcess[i] = am0.kurtosisExcess_as_double(); + } + + Stat st = new Stat(this.rawItemMeans); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.rawItemMeansMean = st.mean_as_double(); + this.rawItemMeansVar = st.variance_as_double(); + this.rawItemMeansSd = Math.sqrt(this.rawItemMeansVar); + this.rawItemMeansMin = st.minimum_as_double(); + this.rawItemMeansMax = st.maximum_as_double(); + this.rawItemMeansRange = this.rawItemMeansMax - this.rawItemMeansMin; + + st = new Stat(this.rawItemStandardDeviations); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.rawItemStandardDeviationsMean = st.mean_as_double(); + this.rawItemStandardDeviationsVar = st.variance_as_double(); + this.rawItemStandardDeviationsSd = Math.sqrt(this.rawItemStandardDeviationsVar); + this.rawItemStandardDeviationsMin = st.minimum_as_double(); + this.rawItemStandardDeviationsMax = st.maximum_as_double(); + this.rawItemStandardDeviationsRange = this.rawItemStandardDeviationsMax - this.rawItemStandardDeviationsMin; + + st = new Stat(this.rawItemVariances); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.rawItemVariancesMean = st.mean_as_double(); + this.rawItemVariancesVar = st.variance_as_double(); + this.rawItemVariancesSd = Math.sqrt(this.rawItemVariancesVar); + this.rawItemVariancesMin = st.minimum_as_double(); + this.rawItemVariancesMax = st.maximum_as_double(); + this.rawItemVariancesRange = this.rawItemVariancesMax - this.rawItemVariancesMin; + + st = new Stat(this.rawItemMinima); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.rawItemMinimaMean = st.mean_as_double(); + this.rawItemMinimaVar = st.variance_as_double(); + this.rawItemMinimaSd = Math.sqrt(this.rawItemMinimaVar); + this.rawItemMinimaMin = st.minimum_as_double(); + this.rawItemMinimaMax = st.maximum_as_double(); + this.rawItemMinimaRange = this.rawItemMinimaMax - this.rawItemMinimaMin; + + st = new Stat(this.rawItemMaxima); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.rawItemMaximaMean = st.mean_as_double(); + this.rawItemMaximaVar = st.variance_as_double(); + this.rawItemMaximaSd = Math.sqrt(this.rawItemMaximaVar); + this.rawItemMaximaMin = st.minimum_as_double(); + this.rawItemMaximaMax = st.maximum_as_double(); + this.rawItemMaximaRange = this.rawItemMaximaMax - this.rawItemMaximaMin; + + st = new Stat(this.rawItemRanges); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.rawItemRangesMean = st.mean_as_double(); + this.rawItemRangesVar = st.variance_as_double(); + this.rawItemRangesSd = Math.sqrt(this.rawItemRangesVar); + this.rawItemRangesMin = st.minimum_as_double(); + this.rawItemRangesMax = st.maximum_as_double(); + this.rawItemRangesRange = this.rawItemRangesMax - this.rawItemRangesMin; + + st = new Stat(this.rawItemTotals); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.rawItemTotalsMean = st.mean_as_double(); + this.rawItemTotalsVar = st.variance_as_double(); + this.rawItemTotalsSd = Math.sqrt(this.rawItemTotalsVar); + this.rawItemTotalsMin = st.minimum_as_double(); + this.rawItemTotalsMax = st.maximum_as_double(); + this.rawItemTotalsRange = this.rawItemTotalsMax - this.rawItemTotalsMin; + + st = new Stat(this.rawItemMedians); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.rawItemMediansMean = st.mean_as_double(); + this.rawItemMediansVar = st.variance_as_double(); + this.rawItemMediansSd = Math.sqrt(this.rawItemMediansVar); + this.rawItemMediansMin = st.minimum_as_double(); + this.rawItemMediansMax = st.maximum_as_double(); + this.rawItemMediansRange = this.rawItemMediansMax - this.rawItemMediansMin; + + this.standardizedItemMeans = new double[this.nItems]; + this.standardizedItemMedians = new double[this.nItems]; + this.standardizedItemStandardDeviations = new double[this.nItems]; + this.standardizedItemVariances = new double[this.nItems]; + this.standardizedItemMinima = new double[this.nItems]; + this.standardizedItemMaxima = new double[this.nItems]; + this.standardizedItemRanges = new double[this.nItems]; + this.standardizedItemTotals = new double[this.nItems]; + this.standardizedItemMomentSkewness = new double[this.nItems]; + this.standardizedItemMedianSkewness = new double[this.nItems]; + this.standardizedItemQuartileSkewness = new double[this.nItems]; + this.standardizedItemKurtosisExcess = new double[this.nItems]; + + for(int i=0; i<this.nItems; i++){ + Stat ams0 = new Stat(this.standardizedScores0[i]); + if(this.nFactorOption){ + ams0.setDenominatorToN(); + } + else{ + ams0.setDenominatorToNminusOne(); + } + this.standardizedItemMeans[i] = 0.0; + this.standardizedItemVariances[i] = 1.0; + this.standardizedItemStandardDeviations[i] = 1.0; + this.standardizedItemMinima[i] = ams0.minimum_as_double(); + this.standardizedItemMaxima[i] = ams0.maximum_as_double(); + this.standardizedItemRanges[i] = this.standardizedItemMaxima[i] - this.standardizedItemMinima[i]; + this.standardizedItemTotals[i] = 0.0; + Stat amss0 = ams0.sort(); + this.standardizedItemMedians[i] = amss0.median_as_double(); + this.standardizedItemMomentSkewness[i] = ams0.momentSkewness_as_double(); + this.standardizedItemMedianSkewness[i] = ams0.medianSkewness_as_double(); + this.standardizedItemQuartileSkewness[i] = ams0.quartileSkewness_as_double(); + this.standardizedItemKurtosisExcess[i] = ams0.kurtosisExcess_as_double(); + } + + + st = new Stat(this.standardizedItemMeans); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.standardizedItemMeansMean = st.mean_as_double(); + this.standardizedItemMeansVar = st.variance_as_double(); + this.standardizedItemMeansSd = Math.sqrt(this.standardizedItemMeansVar); + this.standardizedItemMeansMin = st.minimum_as_double(); + this.standardizedItemMeansMax = st.maximum_as_double(); + this.standardizedItemMeansRange = this.standardizedItemMeansMax - this.standardizedItemMeansMin; + + st = new Stat(this.standardizedItemStandardDeviations); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.standardizedItemStandardDeviationsMean = st.mean_as_double(); + this.standardizedItemStandardDeviationsVar = st.variance_as_double(); + this.standardizedItemStandardDeviationsSd = Math.sqrt(this.standardizedItemStandardDeviationsVar); + this.standardizedItemStandardDeviationsMin = st.minimum_as_double(); + this.standardizedItemStandardDeviationsMax = st.maximum_as_double(); + this.standardizedItemStandardDeviationsRange = this.standardizedItemStandardDeviationsMax - this.standardizedItemStandardDeviationsMin; + + st = new Stat(this.standardizedItemVariances); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.standardizedItemVariancesMean = st.mean_as_double(); + this.standardizedItemVariancesVar = st.variance_as_double(); + this.standardizedItemVariancesSd = Math.sqrt(this.standardizedItemVariancesVar); + this.standardizedItemVariancesMin = st.minimum_as_double(); + this.standardizedItemVariancesMax = st.maximum_as_double(); + this.standardizedItemVariancesRange = this.standardizedItemVariancesMax - this.standardizedItemVariancesMin; + + st = new Stat(this.standardizedItemMinima); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.standardizedItemMinimaMean = st.mean_as_double(); + this.standardizedItemMinimaVar = st.variance_as_double(); + this.standardizedItemMinimaSd = Math.sqrt(this.standardizedItemMinimaVar); + this.standardizedItemMinimaMin = st.minimum_as_double(); + this.standardizedItemMinimaMax = st.maximum_as_double(); + this.standardizedItemMinimaRange = this.standardizedItemMinimaMax - this.standardizedItemMinimaMin; + + st = new Stat(this.standardizedItemMaxima); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.standardizedItemMaximaMean = st.mean_as_double(); + this.standardizedItemMaximaVar = st.variance_as_double(); + this.standardizedItemMaximaSd = Math.sqrt(this.standardizedItemMaximaVar); + this.standardizedItemMaximaMin = st.minimum_as_double(); + this.standardizedItemMaximaMax = st.maximum_as_double(); + this.standardizedItemMaximaRange = this.standardizedItemMaximaMax - this.standardizedItemMaximaMin; + + st = new Stat(this.standardizedItemRanges); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.standardizedItemRangesMean = st.mean_as_double(); + this.standardizedItemRangesVar = st.variance_as_double(); + this.standardizedItemRangesSd = Math.sqrt(this.standardizedItemRangesVar); + this.standardizedItemRangesMin = st.minimum_as_double(); + this.standardizedItemRangesMax = st.maximum_as_double(); + this.standardizedItemRangesRange = this.standardizedItemRangesMax - this.standardizedItemRangesMin; + + this.standardizedItemTotalsMean = 0.0; + this.standardizedItemTotalsVar = 0.0; + this.standardizedItemTotalsSd = 0.0; + this.standardizedItemTotalsMin = 0.0; + this.standardizedItemTotalsMax = 0.0; + this.standardizedItemTotalsRange = 0.0; + + st = new Stat(this.standardizedItemMedians); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.standardizedItemMediansMean = st.mean_as_double(); + this.standardizedItemMediansVar = st.variance_as_double(); + this.standardizedItemMediansSd = Math.sqrt(this.standardizedItemMediansVar); + this.standardizedItemMediansMin = st.minimum_as_double(); + this.standardizedItemMediansMax = st.maximum_as_double(); + this.standardizedItemMediansRange = this.standardizedItemMediansMax - this.standardizedItemMediansMin; + + // INDIVIDUALS + this.rawPersonMeans = new double[this.nPersons]; + this.rawPersonStandardDeviations = new double[this.nPersons]; + this.rawPersonVariances = new double[this.nPersons]; + this.rawPersonMinima = new double[this.nPersons]; + this.rawPersonMaxima = new double[this.nPersons]; + this.rawPersonRanges = new double[this.nPersons]; + this.rawPersonTotals = new double[this.nPersons]; + Stat[] am1 = new Stat[this.nPersons]; + for(int i=0; i<this.nPersons; i++){ + am1[i] = new Stat(this.scores1[i]); + if(this.nFactorOption){ + am1[i].setDenominatorToN(); + } + else{ + am1[i].setDenominatorToNminusOne(); + } + this.rawPersonMeans[i] = am1[i].mean_as_double(); + this.rawPersonVariances[i] = am1[i].variance_as_double(); + this.rawPersonStandardDeviations[i] = Math.sqrt(this.rawPersonVariances[i]); + this.rawPersonMinima[i] = am1[i].minimum_as_double(); + this.rawPersonMaxima[i] = am1[i].maximum_as_double(); + this.rawPersonRanges[i] = this.rawPersonMaxima[i] - this.rawPersonMinima[i]; + this.rawPersonTotals[i] = am1[i].sum_as_double(); + } + + this.standardizedPersonMeans = new double[this.nPersons]; + this.standardizedPersonStandardDeviations = new double[this.nPersons]; + this.standardizedPersonVariances = new double[this.nPersons]; + this.standardizedPersonMinima = new double[this.nPersons]; + this.standardizedPersonMaxima = new double[this.nPersons]; + this.standardizedPersonRanges = new double[this.nPersons]; + this.standardizedPersonTotals = new double[this.nPersons]; + Stat[] ams1 = new Stat[this.nPersons]; + for(int i=0; i<this.nPersons; i++){ + ams1[i] = new Stat(this.standardizedScores1[i]); + if(this.nFactorOption){ + ams1[i].setDenominatorToN(); + } + else{ + ams1[i].setDenominatorToNminusOne(); + } + this.standardizedPersonMeans[i] = ams1[i].mean_as_double(); + this.standardizedPersonVariances[i] = ams1[i].variance_as_double(); + this.standardizedPersonStandardDeviations[i] = Math.sqrt(this.standardizedPersonVariances[i]); + this.standardizedPersonMinima[i] = ams1[i].minimum_as_double(); + this.standardizedPersonMaxima[i] = ams1[i].maximum_as_double(); + this.standardizedPersonRanges[i] = this.standardizedPersonMaxima[i] - this.standardizedPersonMinima[i]; + this.standardizedPersonTotals[i] = ams1[i].sum_as_double(); + } + + + // TOTAL + ArrayMaths am = new ArrayMaths(this.scores0[0]); + for(int i=1; i<this.nItems; i++){ + am = am.concatenate(this.scores0[i]); + } + Stat ams = am.toStat(); + if(this.nFactorOption){ + ams.setDenominatorToN(); + } + else{ + ams.setDenominatorToNminusOne(); + } + this.rawAllResponsesMean = ams.mean_as_double(); + this.rawAllResponsesVariance = ams.variance_as_double(); + this.rawAllResponsesStandardDeviation = Math.sqrt(this.rawAllResponsesVariance); + this.rawAllResponsesMinimum = ams.minimum_as_double(); + this.rawAllResponsesMaximum = ams.maximum_as_double(); + this.rawAllResponsesRange = this.rawAllResponsesMaximum - this.rawAllResponsesMinimum; + this.rawAllResponsesTotal = ams.sum_as_double(); + + ArrayMaths amm = new ArrayMaths(this.standardizedScores0[0]); + for(int i=1; i<this.nItems; i++){ + amm = amm.concatenate(this.standardizedScores0[i]); + } + Stat amss = amm.toStat(); + if(this.nFactorOption){ + amss.setDenominatorToN(); + } + else{ + amss.setDenominatorToNminusOne(); + } + this.standardizedAllResponsesMean = amss.mean_as_double(); + this.standardizedAllResponsesVariance = amss.variance_as_double(); + this.standardizedAllResponsesStandardDeviation = Math.sqrt(this.standardizedAllResponsesVariance); + this.standardizedAllResponsesMinimum = amss.minimum_as_double(); + this.standardizedAllResponsesMaximum = amss.maximum_as_double(); + this.standardizedAllResponsesRange = this.standardizedAllResponsesMaximum - this.standardizedAllResponsesMinimum; + this.standardizedAllResponsesTotal = 0.0; + + this.variancesCalculated = true; + } + + // Get raw data item means + public double[] rawItemMeans(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemMeans; + } + + // Get standardized data item means + public double[] standardizedItemMeans(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemMeans; + } + + public double[] standardisedItemMeans(){ + return this.standardizedItemMeans(); + } + + // Get a raw data item mean + public double rawItemMean(String itemName){ + if(!this.dataPreprocessed)this.preprocessData(); + int index = this.itemIndex(itemName); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemMeans[index-1]; + } + + // Get a raw data item mean + public double rawItemMean(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemMeans[index-1]; + } + + // Get mean of the raw data item means + public double rawMeanOfItemMeans(){ + return rawItemMeansMean; + } + + // Get standard deviation of the raw data item means + public double rawStandardDeviationOfItemMeans(){ + return rawItemMeansSd; + } + + + // Get variance of the raw data item means + public double rawVarianceOfItemMeans(){ + return rawItemMeansVar; + } + + // Get maximum of the raw data item means + public double rawMaximumOfItemMeans(){ + return rawItemMeansMax; + } + + // Get minimum of the raw data item means + public double rawMinimumOfItemMeans(){ + return rawItemMeansMin; + } + + // Get range of the raw data item means + public double rawRangeOfItemMeans(){ + return rawItemMeansRange; + } + + // Get a standardized data item mean + public double standardizedItemMean(String itemName){ + if(!this.dataPreprocessed)this.preprocessData(); + int index = this.itemIndex(itemName); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemMeans[index-1]; + } + + public double standardisedItemMean(String itemName){ + return this.standardizedItemMean(itemName); + } + + // Get a standardized data item mean + public double standardizedItemMean(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemMeans[index-1]; + } + + public double standardisedItemMean(int index){ + return this.standardizedItemMean(index); + } + + // Get mean of the standardized data item means + public double standardizedMeanOfItemMeans(){ + return standardizedItemMeansMean; + } + + public double standardisedMeanOfItemMeans(){ + return standardizedItemMeansMean; + } + + // Get standard deviation of the standardized data item means + public double standardizedStanadarDeviationOfItemMeans(){ + return standardizedItemMeansSd; + } + + public double standardisedStanadarDeviationOfItemMeans(){ + return standardizedItemMeansSd; + } + + // Get variance of the standardized data item means + public double standardizedVarianceOfItemMeans(){ + return standardizedItemMeansVar; + } + + // Get maximum of the standardized data item means + public double standardizedMaximumOfItemMeans(){ + return standardizedItemMeansMax; + } + + public double standardisedVarianceOfItemMeans(){ + return standardizedItemMeansVar; + } + + // Get minimum of the standardized data item means + public double standardizedMinimumOfItemMeans(){ + return standardizedItemMeansMin; + } + + public double standardisedMinimumOfItemMeans(){ + return standardizedItemMeansMin; + } + + // Get range of the standardized data item means + public double standardizedRangeOfItemMeans(){ + return standardizedItemMeansRange; + } + + public double standardisedRangeOfItemMeans(){ + return standardizedItemMeansRange; + } + + // Get raw data item standard deviations + public double[] rawItemStandardDeviations(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemStandardDeviations; + } + + // Get a raw data item standard deviation + public double rawItemStandardDeviation(String itemName){ + if(!this.dataPreprocessed)this.preprocessData(); + int index = this.itemIndex(itemName); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemStandardDeviations[index-1]; + } + + // Get a raw data item standard deviation + public double rawItemStandardDeviation(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemStandardDeviations[index-1]; + } + + // Get mean of the raw data item standard deviation + public double rawMeanOfItemStandardDeviations(){ + return rawItemStandardDeviationsMean; + } + + // Get standard deviation of the raw data item standard deviations + public double rawStanadarDeviationOfItemStandardDeviations(){ + return rawItemStandardDeviationsSd; + } + + // Get variance of the raw data item standard deviations + public double rawVarianceOfItemStandardDeviations(){ + return rawItemStandardDeviationsVar; + } + + // Get maximum of the raw data item standard deviations + public double rawMaximumOfItemStandardDeviations(){ + return rawItemStandardDeviationsMax; + } + + // Get minimum of the raw data item standard deviations + public double rawMinimumOfItemStandardDeviations(){ + return rawItemStandardDeviationsMin; + } + + // Get range of the raw data item standard deviations + public double rawRangeOfItemStandardDeviations(){ + return rawItemStandardDeviationsRange; + } + + // Get standardized data item standard deviations + public double[] standardizedItemStandardDeviations(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemStandardDeviations; + } + + public double[] standardisedItemStandardDeviations(){ + return this.standardizedItemStandardDeviations(); + } + + // Get a standardized data item standard deviation + public double standardizedItemStandardDeviation(String itemName){ + if(!this.dataPreprocessed)this.preprocessData(); + int index = this.itemIndex(itemName); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemStandardDeviations[index-1]; + } + + public double standardisedItemStandardDeviation(String itemName){ + return this.standardizedItemStandardDeviation(itemName); + } + + // Get a standardized data item standard deviation + public double standardizedItemStandardDeviation(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemStandardDeviations[index-1]; + } + + public double standardisedItemStandardDeviation(int index){ + return this.standardizedItemStandardDeviation(index); + } + + // Get mean of the standardized data item standard deviations + public double standardizedMeanOfItemStandardDeviations(){ + return standardizedItemStandardDeviationsMean; + } + + public double standardisedMeanOfItemStandardDeviations(){ + return standardizedItemStandardDeviationsMean; + } + + // Get standard deviation of the standardized data item standard deviations + public double standardizedStanadarDeviationOfItemStandardDeviations(){ + return standardizedItemStandardDeviationsSd; + } + + public double standardisedStanadarDeviationOfItemStandardDeviations(){ + return standardizedItemStandardDeviationsSd; + } + + // Get variance of the standardized data item standard deviations + public double standardizedVarianceOfItemStandardDeviations(){ + return standardizedItemStandardDeviationsVar; + } + + public double standardisedVarianceOfItemStandardDeviations(){ + return standardizedItemStandardDeviationsVar; + } + + // Get maximum of the standardized data item standard deviations + public double standardizedMaximumOfItemStandardDeviations(){ + return standardizedItemStandardDeviationsMax; + } + + public double standardisedMaximumOfItemStandardDeviations(){ + return standardizedItemStandardDeviationsMax; + } + + // Get minimum of the standardized data item standard deviations + public double standardizedMinimumOfItemStandardDeviations(){ + return standardizedItemStandardDeviationsMin; + } + + public double standardisedMinimumOfItemStandardDeviations(){ + return standardizedItemStandardDeviationsMin; + } + + // Get range of the standardized data item standard deviations + public double standardizedRangeOfItemStandardDeviations(){ + return standardizedItemStandardDeviationsRange; + } + + public double standardisedRangeOfItemStandardDeviations(){ + return standardizedItemStandardDeviationsRange; + } + + // Get raw data item variances + public double[] rawItemVariances(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemVariances; + } + + // Get standardized data item variances + public double[] standardizedItemVariances(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemVariances; + } + + // Get standardized data item variances + public double[] standardisedItemVariances(){ + return this.standardizedItemVariances(); + } + + // Get a raw data item variance + public double rawItemVariance(String itemName){ + if(!this.dataPreprocessed)this.preprocessData(); + int index = this.itemIndex(itemName); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemVariances[index-1]; + } + + // Get a raw data item variance + public double rawItemVariance(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemVariances[index-1]; + } + + // Get a standardized data item variance + public double standardizedItemVariance(String itemName){ + if(!this.dataPreprocessed)this.preprocessData(); + int index = this.itemIndex(itemName); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemVariances[index-1]; + } + + public double standardisedItemVariance(String itemName){ + return this.standardizedItemVariance(itemName); + } + + // Get a standardized data item variance + public double standardizedItemVariance(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemVariances[index-1]; + } + + public double standardisedItemVariance(int index){ + return this.standardizedItemVariance(index); + } + + // Get mean of the raw data item variances + public double rawMeanOfItemVariances(){ + return rawItemVariancesMean; + } + + // Get standard deviation of the raw data item variances + public double rawStanadarDeviationOfItemVariances(){ + return rawItemVariancesSd; + } + + // Get variance of the raw data item variances + public double rawVarianceOfItemVariances(){ + return rawItemVariancesVar; + } + + // Get maximum of the raw data item variances + public double rawMaximumOfItemVariances(){ + return rawItemVariancesMax; + } + + // Get minimum of the raw data item variances + public double rawMinimumOfItemVariances(){ + return rawItemVariancesMin; + } + + // Get range of the raw data item variances + public double rawRangeOfItemVariances(){ + return rawItemVariancesRange; + } + + // Get mean of the standardized data item variances + public double standardizedMeanOfItemVariances(){ + return standardizedItemVariancesMean; + } + + public double standardisedMeanOfItemVariances(){ + return standardizedItemVariancesMean; + } + + // Get standard deviation of the standardized data item variances + public double standardizedStanadarDeviationOfItemVariances(){ + return standardizedItemVariancesSd; + } + + public double standardisedStanadarDeviationOfItemVariances(){ + return standardizedItemVariancesSd; + } + + // Get variance of the standardized data item variances + public double standardizedVarianceOfItemVariances(){ + return standardizedItemVariancesVar; + } + + public double standardisedVarianceOfItemVariances(){ + return standardizedItemVariancesVar; + } + + // Get maximum of the standardized data item variances + public double standardizedMaximumOfItemVariances(){ + return standardizedItemVariancesMax; + } + + public double standardisedMaximumOfItemVariances(){ + return standardizedItemVariancesMax; + } + + // Get minimum of the standardized data item variances + public double standardizedMinimumOfItemVariances(){ + return standardizedItemVariancesMin; + } + + public double standardisedMinimumOfItemVariances(){ + return standardizedItemVariancesMin; + } + + // Get range of the standardized data item variances + public double standardizedRangeOfItemVariances(){ + return standardizedItemVariancesRange; + } + + public double standardisedRangeOfItemVariances(){ + return standardizedItemVariancesRange; + } + + // Get raw data item minima + public double[] rawItemMinima(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemMinima; + } + + // Get standardized data item minima + public double[] standardizedItemMinima(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemMinima; + } + + public double[] standardisedItemMinima(){ + return this.standardizedItemMinima(); + } + + // Get a raw data item minimum + public double rawItemMinimum(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemMinima[index-1]; + } + + // Get a standardized data item minimum + public double standardizedItemMinimum(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemMinima[index-1]; + } + + public double standardisedItemMinimum(int index){ + return this.standardizedItemMinimum(index); + } + + // Get mean of the raw data item minima + public double rawMeanOfItemMinima(){ + return rawItemMinimaMean; + } + + // Get standard deviation of the raw data item minima + public double rawStanadarDeviationOfItemMinima(){ + return rawItemMinimaSd; + } + + // Get variance of the raw data item minima + public double rawVarianceOfItemMinima(){ + return rawItemMinimaVar; + } + + // Get maximum of the raw data item minima + public double rawMaximumOfItemMinima(){ + return rawItemMinimaMax; + } + + // Get minimum of the raw data item minima + public double rawMinimumOfItemMinima(){ + return rawItemMinimaMin; + } + + // Get range of the raw data item minima + public double rawRangeOfItemMinima(){ + return rawItemMinimaRange; + } + + // Get mean of the standardized data item minima + public double standardizedMeanOfItemMinima(){ + return standardizedItemMinimaMean; + } + + public double standardisedMeanOfItemMinima(){ + return standardizedItemMinimaMean; + } + + // Get standard deviation of the standardized data item minima + public double standardizedStanadarDeviationOfItemMinima(){ + return standardizedItemMinimaSd; + } + + public double standardisedStanadarDeviationOfItemMinima(){ + return standardizedItemMinimaSd; + } + + // Get variance of the standardized data item minima + public double standardizedVarianceOfItemMinima(){ + return standardizedItemMinimaVar; + } + + public double standardisedVarianceOfItemMinima(){ + return standardizedItemMinimaVar; + } + + // Get maximum of the standardized data item minima + public double standardizedMaximumOfItemMinima(){ + return standardizedItemMinimaMax; + } + + public double standardisedMaximumOfItemMinima(){ + return standardizedItemMinimaMax; + } + + // Get minimum of the standardized data item minima + public double standardizedMinimumOfItemMinima(){ + return standardizedItemMinimaMin; + } + + public double standardisedMinimumOfItemMinima(){ + return standardizedItemMinimaMin; + } + + // Get range of the standardized data item minima + public double standardizedRangeOfItemMinima(){ + return standardizedItemMinimaRange; + } + + public double standardisedRangeOfItemMinima(){ + return standardizedItemMinimaRange; + } + + // Get raw data item maxima + public double[] rawItemMaxima(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemMaxima; + } + + // Get standardized data item maxima + public double[] standardizedItemMaxima(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemMaxima; + } + + public double[] standardisedItemMaxima(){ + return this.standardizedItemMaxima(); + } + + // Get a raw data item maximum + public double rawItemMaximum(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemMaxima[index-1]; + } + + // Get a standardized data item maximum + public double standardizedItemMaximum(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemMaxima[index-1]; + } + + public double standardisedItemMaximum(int index){ + return this.standardizedItemMaximum(index); + } + + // Get mean of the raw data item maxima + public double rawMeanOfItemMaxima(){ + return rawItemMaximaMean; + } + + // Get standard deviation of the raw data item maxima + public double rawStanadarDeviationOfItemMaxima(){ + return rawItemMaximaSd; + } + + // Get variance of the raw data item maxima + public double rawVarianceOfItemMaxima(){ + return rawItemMaximaVar; + } + + // Get maximum of the raw data item maxima + public double rawMaximumOfItemMaxima(){ + return rawItemMaximaMax; + } + + // Get minimum of the raw data item maxima + public double rawMinimumOfItemMaxima(){ + return rawItemMaximaMin; + } + + // Get range of the raw data item maxima + public double rawRangeOfItemMaxima(){ + return rawItemMaximaRange; + } + + // Get mean of the standardized data item maxima + public double standardizedMeanOfItemMaxima(){ + return standardizedItemMaximaMean; + } + + public double standardisedMeanOfItemMaxima(){ + return standardizedItemMaximaMean; + } + + // Get standard deviation of the standardized data item maxima + public double standardizedStanadarDeviationOfItemMaxima(){ + return standardizedItemMaximaSd; + } + + public double standardisedStanadarDeviationOfItemMaxima(){ + return standardizedItemMaximaSd; + } + + // Get variance of the standardized data item maxima + public double standardizedVarianceOfItemMaxima(){ + return standardizedItemMaximaVar; + } + + public double standardisedVarianceOfItemMaxima(){ + return standardizedItemMaximaVar; + } + + // Get maximum of the standardized data item maxima + public double standardizedMaximumOfItemMaxima(){ + return standardizedItemMaximaMax; + } + + public double standardisedMaximumOfItemMaxima(){ + return standardizedItemMaximaMax; + } + + // Get minimum of the standardized data item maxima + public double standardizedMinimumOfItemMaxima(){ + return standardizedItemMaximaMin; + } + + public double standardisedMinimumOfItemMaxima(){ + return standardizedItemMaximaMin; + } + + // Get range of the standardized data item maxima + public double standardizedRangeOfItemMaxima(){ + return standardizedItemMaximaRange; + } + + public double standardisedRangeOfItemMaxima(){ + return standardizedItemMaximaRange; + } + + // Get raw data item ranges + public double[] rawItemRanges(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemRanges; + } + + // Get standardized data item ranges + public double[] standardizedItemRanges(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemRanges; + } + + public double[] standardisedItemRanges(){ + return standardizedItemRanges(); + } + + // Get a raw data item range + public double rawItemRange(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemRanges[index-1]; + } + + // Get a standardized data item range + public double standardizedItemRange(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemRanges[index-1]; + } + + public double standardisedItemRange(int index){ + return this.standardizedItemRange(index); + } + + // Get mean of the raw data item ranges + public double rawMeanOfItemRanges(){ + return rawItemRangesMean; + } + + // Get standard deviation of the raw data item ranges + public double rawStanadarDeviationOfItemRanges(){ + return rawItemRangesSd; + } + + // Get variance of the raw data item ranges + public double rawVarianceOfItemRanges(){ + return rawItemRangesVar; + } + + // Get maximum of the raw data item ranges + public double rawMaximumOfItemRanges(){ + return rawItemRangesMax; + } + + // Get minimum of the raw data item ranges + public double rawMinimumOfItemRanges(){ + return rawItemRangesMin; + } + + // Get range of the raw data item ranges + public double rawRangeOfItemRanges(){ + return rawItemRangesRange; + } + + // Get mean of the standardized data item ranges + public double standardizedMeanOfItemRanges(){ + return standardizedItemRangesMean; + } + + public double standardisedMeanOfItemRanges(){ + return standardizedItemRangesMean; + } + + // Get standard deviation of the standardized data item ranges + public double standardizedStanadarDeviationOfItemRanges(){ + return standardizedItemRangesSd; + } + + public double standardisedStanadarDeviationOfItemRanges(){ + return standardizedItemRangesSd; + } + + // Get variance of the standardized data item ranges + public double standardizedVarianceOfItemRanges(){ + return standardizedItemRangesVar; + } + + public double standardisedVarianceOfItemRanges(){ + return standardizedItemRangesVar; + } + + // Get maximum of the standardized data item ranges + public double standardizedMaximumOfItemRanges(){ + return standardizedItemRangesMax; + } + + public double standardisedMaximumOfItemRanges(){ + return standardizedItemRangesMax; + } + + // Get minimum of the standardized data item ranges + public double standardizedMinimumOfItemRanges(){ + return standardizedItemRangesMin; + } + + public double standardisedMinimumOfItemRanges(){ + return standardizedItemRangesMin; + } + + // Get range of the standardized data item ranges + public double standardizedRangeOfItemRanges(){ + return standardizedItemRangesRange; + } + + public double standardisedRangeOfItemRanges(){ + return standardizedItemRangesRange; + } + + // Get raw data item totals + public double[] rawItemTotals(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemTotals; + } + + // Get standardized data item totals + public double[] standardizedItemTotals(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemTotals; + } + + public double[] standardisedItemTotals(){ + return this.standardizedItemTotals(); + } + + // Get a raw data item total + public double rawItemTotal(String itemName){ + if(!this.dataPreprocessed)this.preprocessData(); + int index = this.itemIndex(itemName); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemTotals[index-1]; + } + + // Get a raw data item total + public double rawItemTotal(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemTotals[index-1]; + } + + // Get a standardized data item total + public double standardizedItemTotal(String itemName){ + if(!this.dataPreprocessed)this.preprocessData(); + int index = this.itemIndex(itemName); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemTotals[index-1]; + } + + public double standardisedItemTotal(String itemName){ + return standardizedItemTotal(itemName); + } + + // Get a standardized data item total + public double standardizedItemTotal(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemTotals[index-1]; + } + + public double standardisedItemTotal(int index){ + return this.standardizedItemTotal(index); + } + + // Get mean of the raw data item totals + public double rawMeanOfItemTotals(){ + return rawItemTotalsMean; + } + + // Get standard deviation of the raw data item totals + public double rawStanadarDeviationOfItemTotals(){ + return rawItemTotalsSd; + } + + // Get variance of the raw data item totals + public double rawVarianceOfItemTotals(){ + return rawItemTotalsVar; + } + + // Get maximum of the raw data item totals + public double rawMaximumOfItemTotals(){ + return rawItemTotalsMax; + } + + // Get minimum of the raw data item totals + public double rawMinimumOfItemTotals(){ + return rawItemTotalsMin; + } + + // Get range of the raw data item totals + public double rawRangeOfItemTotals(){ + return rawItemTotalsRange; + } + + // Get mean of the standardized data item totals + public double standardizedMeanOfItemTotals(){ + return standardizedItemTotalsMean; + } + + public double standardisedMeanOfItemTotals(){ + return standardizedItemTotalsMean; + } + + // Get standard deviation of the standardized data item totals + public double standardizedStanadarDeviationOfItemTotals(){ + return standardizedItemTotalsSd; + } + + public double standardisedStanadarDeviationOfItemTotals(){ + return standardizedItemTotalsSd; + } + + // Get variance of the standardized data item totals + public double standardizedVarianceOfItemTotals(){ + return standardizedItemTotalsVar; + } + + public double standardisedVarianceOfItemTotals(){ + return standardizedItemTotalsVar; + } + + // Get maximum of the standardized data item totals + public double standardizedMaximumOfItemTotals(){ + return standardizedItemTotalsMax; + } + + public double standardisedMaximumOfItemTotals(){ + return standardizedItemTotalsMax; + } + + // Get minimum of the standardized data item totals + public double standardizedMinimumOfItemTotals(){ + return standardizedItemTotalsMin; + } + + public double standardisedMinimumOfItemTotals(){ + return standardizedItemTotalsMin; + } + + // Get range of the standardized data item totals + public double standardizedRangeOfItemTotals(){ + return standardizedItemTotalsRange; + } + + public double standardisedRangeOfItemTotals(){ + return standardizedItemTotalsRange; + } + + // Get raw data person means + public double[] rawPersonMeans(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawPersonMeans; + } + + // Get standardized data person means + public double[] standardizedPersonMeans(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedPersonMeans; + } + + public double[] standardisedPersonMeans(){ + return this.standardizedPersonMeans(); + } + + // Get a raw data person mean + public double rawPersonMean(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nPersons)throw new IllegalArgumentException("The person index, " + index + ", must lie between 1 and the number of persons," + this.nPersons + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawPersonMeans[index-1]; + } + + // Get a standardized data person mean + public double standardizedPersonMean(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nPersons)throw new IllegalArgumentException("The person index, " + index + ", must lie between 1 and the number of persons," + this.nPersons + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedPersonMeans[index-1]; + } + + public double standardisedPersonMean(int index){ + return this.standardizedPersonMean(index); + } + + // Get raw data person standard deviations + public double[] rawPersonStandardDeviations(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawPersonStandardDeviations; + } + + // Get standardized data person standard deviations + public double[] standardizedPersonStandardDeviations(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedPersonStandardDeviations; + } + + public double[] standardisedPersonStandardDeviations(){ + return this.standardizedPersonStandardDeviations(); + } + + // Get a raw data person standard deviation + public double rawPersonStandardDeviation(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nPersons)throw new IllegalArgumentException("The person index, " + index + ", must lie between 1 and the number of persons," + this.nPersons + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawPersonStandardDeviations[index-1]; + } + + // Get a standardized data person standard deviation + public double standardizedPersonStandardDeviation(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nPersons)throw new IllegalArgumentException("The person index, " + index + ", must lie between 1 and the number of persons," + this.nPersons + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedPersonStandardDeviations[index-1]; + } + + public double standardisedPersonStandardDeviation(int index){ + return this.standardizedPersonStandardDeviation(index); + } + + // Get raw data person variances + public double[] rawPersonVariances(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawPersonVariances; + } + + // Get standardized data person variances + public double[] standardizedPersonVariances(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedPersonVariances; + } + + public double[] standardisedPersonVariances(){ + return this.standardizedPersonVariances(); + } + + // Get a raw data person variance + public double rawPersonVariance(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nPersons)throw new IllegalArgumentException("The person index, " + index + ", must lie between 1 and the number of persons," + this.nPersons + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawPersonVariances[index-1]; + } + + // Get a standardized data person variance + public double standardizedPersonVariance(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nPersons)throw new IllegalArgumentException("The person index, " + index + ", must lie between 1 and the number of persons," + this.nPersons + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedPersonVariances[index-1]; + } + + public double standardisedPersonVariance(int index){ + return this.standardizedPersonVariance(index); + } + + // Get raw data person minima + public double[] rawPersonMinima(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawPersonMinima; + } + + // Get standardized data person minima + public double[] standardizedPersonMinima(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedPersonMinima; + } + + public double[] standardisedPersonMinima(){ + return this.standardisedPersonMinima(); + } + + // Get a raw data person minimum + public double rawPersonMinimum(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The person index, " + index + ", must lie between 1 and the number of persons," + this.nPersons + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawPersonMinima[index-1]; + } + + // Get a standardized data person minimum + public double standardizedPersonMinimum(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nPersons)throw new IllegalArgumentException("The person index, " + index + ", must lie between 1 and the number of persons," + this.nPersons + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedPersonMinima[index-1]; + } + + public double standardisedPersonMinimum(int index){ + return this.standardizedPersonMinimum(index); + } + + // Get raw data person maxima + public double[] rawPersonMaxima(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawPersonMaxima; + } + + // Get standardized data person maxima + public double[] standardizedPersonMaxima(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedPersonMaxima; + } + + public double[] standardisedPersonMaxima(){ + return this.standardizedPersonMaxima(); + } + + // Get a raw data person maximum + public double rawPersonMaximum(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The person index, " + index + ", must lie between 1 and the number of persons," + this.nPersons + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawPersonMaxima[index-1]; + } + + // Get a standardized data person maximum + public double standardizedPersonMaximum(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nPersons)throw new IllegalArgumentException("The person index, " + index + ", must lie between 1 and the number of persons," + this.nPersons + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedPersonMaxima[index-1]; + } + + public double standardisedPersonMaximum(int index){ + return this.standardizedPersonMaximum(index); + } + + // Get raw data person ranges + public double[] rawPersonRanges(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawPersonRanges; + } + + // Get standardized data person ranges + public double[] standardizedPersonRanges(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedPersonRanges; + } + + public double[] standardisedPersonRanges(){ + return this.standardizedPersonRanges(); + } + + // Get a raw data person range + public double rawPersonRange(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The person index, " + index + ", must lie between 1 and the number of persons," + this.nPersons + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawPersonRanges[index-1]; + } + + // Get a standardized data person range + public double standardizedPersonRange(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nPersons)throw new IllegalArgumentException("The person index, " + index + ", must lie between 1 and the number of persons," + this.nPersons + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedPersonRanges[index-1]; + } + + public double standardisedPersonRange(int index){ + return this.standardizedPersonRange(index); + } + + // Get raw data item medians + public double[] rawItemMedians(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemMedians; + } + + // Get standardized data item medians + public double[] standardizedItemMedians(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemMedians; + } + + public double[] standardisedItemMedians(){ + return this.standardizedItemMedians(); + } + + // Get a raw data item median + public double rawItemMedian(String itemName){ + if(!this.dataPreprocessed)this.preprocessData(); + int index = this.itemIndex(itemName); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemMedians[index-1]; + } + + // Get a raw data item median + public double rawItemMedian(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawItemMedians[index-1]; + } + + // Get a standardized data item median + public double standardizedItemMedian(String itemName){ + if(!this.dataPreprocessed)this.preprocessData(); + int index = this.itemIndex(itemName); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemMedians[index-1]; + } + + public double standardisedItemMedian(String itemName){ + return standardizedItemMedian(itemName); + } + + // Get a standardized data item median + public double standardizedItemMedian(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The item index, " + index + ", must lie between 1 and the number of items," + this.nItems + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedItemMedians[index-1]; + } + + public double standardisedItemMedian(int index){ + return this.standardizedItemMedian(index); + } + + // Get mean of the raw data item medians + public double rawMeanOfItemMedians(){ + return rawItemMediansMean; + } + + // Get standard deviation of the raw data item medians + public double rawStanadarDeviationOfItemMedians(){ + return rawItemMediansSd; + } + + // Get variance of the raw data item medians + public double rawVarianceOfItemMedians(){ + return rawItemMediansVar; + } + + // Get maximum of the raw data item medians + public double rawMaximumOfItemMedians(){ + return rawItemMediansMax; + } + + // Get minimum of the raw data item medians + public double rawMinimumOfItemMedians(){ + return rawItemMediansMin; + } + + // Get range of the raw data item medians + public double rawRangeOfItemMedians(){ + return rawItemMediansRange; + } + + // Get mean of the standardized data item medians + public double standardizedMeanOfItemMedians(){ + return standardizedItemMediansMean; + } + + public double standardisedMeanOfItemMedians(){ + return standardizedItemMediansMean; + } + + // Get standard deviation of the standardized data item medians + public double standardizedStanadarDeviationOfItemMedians(){ + return standardizedItemMediansSd; + } + + public double standardisedStanadarDeviationOfItemMedians(){ + return standardizedItemMediansSd; + } + + // Get variance of the standardized data item medians + public double standardizedVarianceOfItemMedians(){ + return standardizedItemMediansVar; + } + + public double standardisedVarianceOfItemMedians(){ + return standardizedItemMediansVar; + } + + // Get maximum of the standardized data item medians + public double standardizedMaximumOfItemMedians(){ + return standardizedItemMediansMax; + } + + public double standardisedMaximumOfItemMedians(){ + return standardizedItemMediansMax; + } + + // Get minimum of the standardized data item medians + public double standardizedMinimumOfItemMedians(){ + return standardizedItemMediansMin; + } + + public double standardisedMinimumOfItemMedians(){ + return standardizedItemMediansMin; + } + + // Get range of the standardized data item medians + public double standardizedRangeOfItemMedians(){ + return standardizedItemMediansRange; + } + + public double standardisedRangeOfItemMedians(){ + return standardizedItemMediansRange; + } + + // Get raw data person totals + public double[] rawPersonTotals(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawPersonTotals; + } + + // Get standardized data person totals + public double[] standardizedPersonTotals(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedPersonTotals; + } + + public double[] standardisedPersonTotals(){ + return this.standardizedPersonTotals(); + } + + // Get a raw data person total + public double rawPersonTotal(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The person index, " + index + ", must lie between 1 and the number of persons," + this.nPersons + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawPersonTotals[index-1]; + } + + // Get a standardized data person total + public double standardizedPersonTotal(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nPersons)throw new IllegalArgumentException("The person index, " + index + ", must lie between 1 and the number of persons," + this.nPersons + ", inclusive"); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedPersonTotals[index-1]; + } + + public double standardisedPersonTotal(int index){ + return this.standardizedPersonTotal(index); + } + + // Get raw data total mean + public double rawAllResponsesMean(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawAllResponsesMean; + } + + // Get standardized data total mean + public double standardizedAllResponsesMean(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedAllResponsesMean; + } + + public double standardisedTotalMean(){ + return this.standardizedAllResponsesMean(); + } + + // Get raw data total standard deviation + public double rawAllResponsesStandardDeviation(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawAllResponsesStandardDeviation; + } + + // Get standardized data total standard deviation + public double standardizedAllResponsesStandardDeviation(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedAllResponsesStandardDeviation; + } + + public double standardisedTotalStandardDeviation(){ + return this.standardizedAllResponsesStandardDeviation(); + } + + // Get raw data total variance + public double rawAllResponsesVariance(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawAllResponsesVariance; + } + + // Get standardized data total variance + public double standardizedAllResponsesVariance(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedAllResponsesVariance; + } + + public double standardisedTotalVariance(){ + return this.standardizedAllResponsesVariance(); + } + + // Get raw data total minimum + public double rawAllResponsesMinimum(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawAllResponsesMinimum; + } + + // Get standardized data total minimum + public double standardizedAllResponsesMinimum(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedAllResponsesMinimum; + } + + public double standardisedTotalMinimum(){ + return this.standardizedAllResponsesMinimum(); + } + + // Get raw data total maximum + public double rawAllResponsesMaximum(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawAllResponsesMaximum; + } + + // Get standardized data total maximum + public double standardizedAllResponsesMaximum(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedAllResponsesMaximum; + } + + public double standardisedTotalMaximum(){ + return this.standardizedAllResponsesMaximum(); + } + + // Get raw data total range + public double rawAllResponsesRange(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawAllResponsesRange; + } + + // Get standardized data total range + public double standardizedAllResponsesRange(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedAllResponsesRange; + } + + public double standardisedTotalRange(){ + return this.standardizedAllResponsesRange(); + } + + // Get raw data total total + public double rawAllResponsesTotal(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.rawAllResponsesTotal; + } + + // Get standardized data total total + public double standardizedAllResponsesTotal(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.variancesCalculated)this.meansAndVariances(); + return this.standardizedAllResponsesTotal; + } + + public double standardisedTotalTotal(){ + return this.standardizedAllResponsesTotal(); + } + + // COVARIANCES AND CORRELATION COEFFICIENTS + // Calculate covariances and correlation coefficints between items + protected void covariancesAndCorrelationCoefficients(){ + // Covariances + this.rawCovariances = new double[this.nItems+1][this.nItems+1]; + // raw data item-item covariance + for(int i=0; i<this.nItems; i++){ + for(int j=i; j<this.nItems; j++){ + this.rawCovariances[i][j] = Stat.covariance(this.scores0[i], this.scores0[j]); + if(i!=j)this.rawCovariances[j][i] = this.rawCovariances[i][j]; + } + } + + // raw data item-(item total) covariances + for(int i=0; i<this.nItems; i++){ + this.rawCovariances[i][this.nItems] = Stat.covariance(this.scores0[i], this.rawPersonTotals); + this.rawCovariances[this.nItems][i] = this.rawCovariances[i][this.nItems]; + } + this.rawCovariances[this.nItems][this.nItems] = Stat.covariance(this.rawPersonTotals, this.rawPersonTotals); + + // standardized data item-item covariances + this.standardizedCovariances = new double[this.nItems+1][this.nItems+1]; + for(int i=0; i<this.nItems; i++){ + for(int j=i; j<this.nItems; j++){ + this.standardizedCovariances[i][j] = Stat.covariance(this.scores0[i], this.scores0[j]); + if(i!=j)this.standardizedCovariances[j][i] = this.standardizedCovariances[i][j]; + } + } + + // standardized data item-(item totals) covariances + for(int i=0; i<this.nItems; i++){ + this.standardizedCovariances[i][this.nItems] = Stat.covariance(this.scores0[i], this.standardizedPersonTotals); + this.standardizedCovariances[this.nItems][i] = this.standardizedCovariances[i][this.nItems]; + } + this.standardizedCovariances[this.nItems][this.nItems] = Stat.covariance(this.standardizedPersonTotals, this.standardizedPersonTotals); + + + // Correlation coefficients + this.rawCorrelationCoefficients = new double[this.nItems+1][this.nItems+1]; + + // Raw data inter-item correlation coefficients + for(int i=0; i<this.nItems; i++){ + this.rawCorrelationCoefficients[i][i] = 1.0; + for(int j=i+1; j<this.nItems; j++){ + this.rawCorrelationCoefficients[i][j] = this.rawCovariances[i][j]/Math.sqrt(this.rawCovariances[i][i]*this.rawCovariances[j][j]); + this.rawCorrelationCoefficients[j][i] = this.rawCorrelationCoefficients[i][j]; + } + } + + // Raw data item-(item totals) correlation coefficients + for(int i=0; i<this.nItems; i++){ + this.rawCorrelationCoefficients[i][this.nItems] = this.rawCovariances[i][this.nItems]/Math.sqrt(this.rawCovariances[i][i]*this.rawCovariances[this.nItems][this.nItems]); + this.rawCorrelationCoefficients[this.nItems][i] = this.rawCorrelationCoefficients[i][this.nItems]; + } + this.rawCorrelationCoefficients[this.nItems][this.nItems] = 1.0; + + // Average of the raw data inter-item correlation coefficients + double[] rhoArray = new double[this.nItems*(this.nItems-1)/2]; + int kk=0; + for(int i=0; i<this.nItems; i++){ + for(int j=i+1; j<this.nItems; j++){ + rhoArray[kk] = this.rawCorrelationCoefficients[i][j]; + kk++; + } + } + Stat st = new Stat(rhoArray); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.rawMeanRhoWithoutTotals = st.mean_as_double(); + this.rawStandardDeviationRhoWithoutTotals = st.standardDeviation_as_double(); + + rhoArray = new double[this.nItems*(this.nItems+1)/2]; + kk=0; + for(int i=0; i<=this.nItems; i++){ + for(int j=i+1; j<=this.nItems; j++){ + rhoArray[kk] = this.rawCorrelationCoefficients[i][j]; + kk++; + } + } + st = new Stat(rhoArray); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.rawMeanRhoWithTotals = st.mean_as_double(); + this.rawStandardDeviationRhoWithTotals = st.standardDeviation_as_double(); + + // Standardized data inter-item correlation coefficients + this.standardizedCorrelationCoefficients = new double[this.nItems+1][this.nItems+1]; + + for(int i=0; i<this.nItems; i++){ + this.standardizedCorrelationCoefficients[i][i] = 1.0; + for(int j=i+1; j<this.nItems; j++){ + this.standardizedCorrelationCoefficients[i][j] = this.standardizedCovariances[i][j]/Math.sqrt(this.standardizedCovariances[i][i]*this.standardizedCovariances[j][j]); + this.standardizedCorrelationCoefficients[j][i] = this.standardizedCorrelationCoefficients[i][j]; + } + } + + // Standardized data item-(item totals) correlation coefficients + for(int i=0; i<this.nItems; i++){ + this.standardizedCorrelationCoefficients[i][this.nItems] = this.standardizedCovariances[i][this.nItems]/Math.sqrt(this.standardizedCovariances[i][i]*this.standardizedCovariances[this.nItems][this.nItems]); + this.standardizedCorrelationCoefficients[this.nItems][i] = this.standardizedCorrelationCoefficients[i][this.nItems]; + } + this.standardizedCorrelationCoefficients[this.nItems][this.nItems] = 1.0; + + // Average of the standardized data inter-item correlation coefficients + rhoArray = new double[this.nItems*(this.nItems-1)/2]; + kk=0; + for(int i=0; i<this.nItems; i++){ + for(int j=i+1; j<this.nItems; j++){ + rhoArray[kk] = this.standardizedCorrelationCoefficients[i][j]; + kk++; + } + } + st = new Stat(rhoArray); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.standardizedMeanRhoWithoutTotals = st.mean_as_double(); + this.standardizedStandardDeviationRhoWithoutTotals = st.standardDeviation_as_double(); + + rhoArray = new double[this.nItems*(this.nItems+1)/2]; + kk=0; + for(int i=0; i<=this.nItems; i++){ + for(int j=i+1; j<=this.nItems; j++){ + rhoArray[kk] = this.standardizedCorrelationCoefficients[i][j]; + kk++; + } + } + st = new Stat(rhoArray); + if(this.nFactorOption){ + st.setDenominatorToN(); + } + else{ + st.setDenominatorToNminusOne(); + } + this.standardizedMeanRhoWithTotals = st.mean_as_double(); + this.standardizedStandardDeviationRhoWithTotals = st.standardDeviation_as_double(); + + this.covariancesCalculated = true; + } + + // Get the raw data covariances + public double[][] rawCovariances(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.rawCovariances; + } + + // Get the standardized data covariances + public double[][] standardizedCovariances(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.standardizedCovariances; + } + + public double[][] standardisedCovariances(){ + return this.standardizedCovariances(); + } + + // Get the raw data covariance of two items + public double rawCovariance(String itemName1, String itemName2){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + int index1 = this.itemIndex(itemName1); + int index2 = this.itemIndex(itemName2); + return this.rawCovariances[index1-1][index2-1]; + } + + // Get the raw data covariance of two items + public double rawCovariance(int index1, int index2){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index1<1 || index1>this.nItems)throw new IllegalArgumentException("The first item index, " + index1 + ", must lie between 1 and the number of items plus one (for totals)," + (this.nItems+1) + ", inclusive"); + if(index2<1 || index2>this.nItems)throw new IllegalArgumentException("The second item index, " + index2 + ", must lie between 1 and the number of items plus one (for totals)," + (this.nItems+1) + ", inclusive"); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.rawCovariances[index1-1][index2-1]; + } + + // Get the raw data covariance of an item and the toals of the items + public double rawCovariance(String itemName){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + int index = this.itemIndex(itemName); + return this.rawCovariances[index-1][this.nItems]; + } + + // Get the raw data covariance of an item and the toals of the items + public double rawCovariance(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index< 1 || index>this.nItems)throw new IllegalArgumentException("The first item index, " + index + ", must lie between 1 and the number of items plus one (for totals)," + (this.nItems+1) + ", inclusive"); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.rawCovariances[index-1][this.nItems]; + } + + // Get the standardized data covariance of two items + public double standardizedCovariance(String itemName1, String itemName2){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + int index1 = this.itemIndex(itemName1); + int index2 = this.itemIndex(itemName2); + return this.standardizedCovariances[index1+1][index2+1]; + } + + public double standardisedCovariance(String itemName1, String itemName2){ + return this.standardizedCovariance(itemName1, itemName2); + } + + // Get the standardized data covariance of two items + public double standardizedCovariance(int index1, int index2){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index1<1 || index1>this.nItems)throw new IllegalArgumentException("The first item index, " + index1 + ", must lie between 1 and the number of items plus one (for totals)," + (this.nItems+1) + ", inclusive"); + if(index2<1 || index2>this.nItems)throw new IllegalArgumentException("The second item index, " + index2 + ", must lie between 1 and the number of items plus one (for totals)," + (this.nItems+1) + ", inclusive"); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.standardizedCovariances[index1+1][index2+1]; + } + + public double standardisedCovariance(int index1, int index2){ + return this.standardizedCovariance(index1, index2); + } + + // Get the standardized data covariance of an item and the toals of the items + public double standardizedCovariance(String itemName){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + int index = this.itemIndex(itemName); + return this.standardizedCovariances[index+1][this.nItems]; + } + + public double standardisedCovariance(String itemName){ + return this.standardizedCovariance(itemName); + } + + // Get the standardized data covariance of an item and the totals of the items + public double standardizedCovariance(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The first item index, " + index + ", must lie between 1 and the number of items plus one (for totals)," + (this.nItems+1) + ", inclusive"); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.standardizedCovariances[index+1][this.nItems]; + } + + public double standardisedCovariance(int index){ + return this.standardizedCovariance(index); + } + + // Get the raw data average correlation coefficient excluding totals + public double rawAverageCorrelationCoefficients(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.rawMeanRhoWithoutTotals; + } + + // Get the raw data standardard deviation of the correlation coefficient excluding totals + public double rawStandardDeviationCorrelationCoefficients(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.rawStandardDeviationRhoWithoutTotals; + } + + // Get the standardized data average correlation coefficient excluding totals + public double standardizedAverageCorrelationCoefficients(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.standardizedMeanRhoWithoutTotals; + } + + public double standardisedAverageCorrelationCoefficients(){ + return this.standardizedAverageCorrelationCoefficients(); + } + + // Get the standardized data standardard deviation of the correlation coefficient excluding totals + public double standardizedStandardDeviationCorrelationCoefficients(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.standardizedStandardDeviationRhoWithoutTotals; + } + + public double standardisedStandardDeviationCorrelationCoefficients(){ + return this.standardizedStandardDeviationCorrelationCoefficients(); + } + + // Get the raw data average correlation coefficient including totals + public double rawAverageCorrelationCoefficientsWithTotals(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.rawMeanRhoWithTotals; + } + + // Get the raw data standardard deviation of the correlation coefficient including totals + public double rawStandardDeviationCorrelationCoefficientsWithTotals(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.rawStandardDeviationRhoWithTotals; + } + + // Get the standardized data average correlation coefficient including totals + public double standardizedAverageCorrelationCoefficientsWithTotals(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.standardizedMeanRhoWithTotals; + } + + public double standardisedAverageCorrelationCoefficientsWithTotals(){ + return this.standardizedAverageCorrelationCoefficientsWithTotals(); + } + + // Get the standardized data standardard deviation of the correlation coefficient including totals + public double standardizedStandardDeviationCorrelationCoefficientsWithTotals(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.standardizedStandardDeviationRhoWithTotals; + } + + public double standardisedStandardDeviationCorrelationCoefficientsWithTotals(){ + return this.standardizedStandardDeviationCorrelationCoefficientsWithTotals(); + } + + // Get the raw data correlation coefficients + public double[][] rawCorrelationCoefficients(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.rawCorrelationCoefficients; + } + + + // Get the standardized data correlation coefficients + public double[][] standardizedCorrelationCoefficients(){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.standardizedCorrelationCoefficients; + } + + public double[][] standardisedCorrelationCoefficients(){ + return this.standardizedCorrelationCoefficients(); + } + + // Get the raw data correlation coefficient of two items + public double rawCorrelationCoefficient(String itemName1, String itemName2){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + int index1 = this.itemIndex(itemName1); + int index2 = this.itemIndex(itemName2); + return this.rawCorrelationCoefficients[index1-1][index2-1]; + } + + // Get the raw data correlation coefficient of two items + public double rawCorrelationCoefficient(int index1, int index2){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index1<1 || index1>this.nItems)throw new IllegalArgumentException("The first item index, " + index1 + ", must lie between 1 and the number of items plus one (for totals)," + (this.nItems+1) + ", inclusive"); + if(index2<1 || index2>this.nItems)throw new IllegalArgumentException("The second item index, " + index2 + ", must lie between 1 and the number of items plus one (for totals)," + (this.nItems+1) + ", inclusive"); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.rawCorrelationCoefficients[index1-1][index2-1]; + } + + // Get the raw data correlation coefficient of an item and the totals of the items` + public double rawCorrelationCoefficient(String itemName){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + int index = this.itemIndex(itemName); + return this.rawCorrelationCoefficients[index-1][this.nItems]; + } + + // Get the raw data correlation coefficient of an item and the totals of the items` + public double rawCorrelationCoefficient(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The first item index, " + index + ", must lie between 1 and the number of items plus one (for totals)," + (this.nItems+1) + ", inclusive"); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.rawCorrelationCoefficients[index-1][this.nItems]; + } + + // Get the standardized data correlation coefficient of two items + public double standardizedCorrelationCoefficient(String itemName1, String itemName2){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + int index1 = this.itemIndex(itemName1); + int index2 = this.itemIndex(itemName2); + return this.standardizedCorrelationCoefficients[index1+1][index2+1]; + } + + public double standardisedCorrelationCoefficient(String itemName1, String itemName2){ + return this.standardizedCorrelationCoefficient(itemName1, itemName2); + } + + // Get the standardized data correlation coefficient of two items + public double standardizedCorrelationCoefficient(int index1, int index2){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index1<1 || index1>this.nItems)throw new IllegalArgumentException("The first item index, " + index1 + ", must lie between 1 and the number of items plus one (for totals)," + (this.nItems+1) + ", inclusive"); + if(index2<1 || index2>this.nItems)throw new IllegalArgumentException("The second item index, " + index2 + ", must lie between 1 and the number of items plus one (for totals)," + (this.nItems+1) + ", inclusive"); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.standardizedCorrelationCoefficients[index1+1][index2+1]; + } + + public double standardisedCorrelationCoefficient(int index1, int index2){ + return this.standardizedCorrelationCoefficient(index1, index2); + } + + // Get the standardized data correlation coefficient of an item and the totals of the items` + public double standardizedCorrelationCoefficient(String itemName){ + if(!this.dataPreprocessed)this.preprocessData(); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + int index = this.itemIndex(itemName); + return this.standardizedCorrelationCoefficients[index+1][this.nItems]; + } + + public double standardisedCorrelationCoefficient(String itemName){ + return this.standardizedCorrelationCoefficient(itemName); + } + + // Get the standardized data correlation coefficient of an item and the totals of the items` + public double standardizedCorrelationCoefficient(int index){ + if(!this.dataPreprocessed)this.preprocessData(); + if(index<1 || index>this.nItems)throw new IllegalArgumentException("The first item index, " + index + ", must lie between 1 and the number of items plus one (for totals)," + (this.nItems+1) + ", inclusive"); + if(!this.covariancesCalculated)this.covariancesAndCorrelationCoefficients(); + return this.standardizedCorrelationCoefficients[index+1][this.nItems]; + } + + public double standardisedCorrelationCoefficient(int index){ + return this.standardizedCorrelationCoefficient(index); + } + + + // Check which of the original items are dichotomous + protected double[] checkWhetherRawItemsDichotomous(){ + + if(!this.dichotomousCheckDone){ + this.dichotomous = new boolean[this.nItems]; + this.dichotomousPercentage = new double[this.nItems]; + int nDich = 0; + for(int k=0; k<this.nItems; k++){ + this.dichotomousPercentage[k] = this.checkWhetherDichotomous(this.scores0[k]); + if(this.dichotomousPercentage[k]==100.0){ + this.dichotomous[k]=true; + nDich++; + } + } + if(nDich==this.nItems)this.dichotomousOverall = true; + + this.dichotomousCheckDone = false; + } + return this.dichotomousPercentage; + } + + // Check wheteher an array of data is dichotomous + // returns percetage responses that are dichotomous + protected double checkWhetherDichotomous(double[] array){ + + int n = array.length; + double[] responseMatching = new double[n]; + boolean[] matchingCheck = new boolean[n]; + + for(int i=0; i<n; i++){ + responseMatching[i] = 0.0; + matchingCheck[i] = false; + } + + for(int i=0; i<n; i++){ + responseMatching[i] = 0; + for(int j=0; j<n; j++){ + if(array[i]==array[j] && !matchingCheck[j]){ + responseMatching[i] += 1.0; + matchingCheck[j] = true; + } + } + } + + ArrayMaths am0 = new ArrayMaths(responseMatching); + ArrayMaths am1 = am0.sort(); + double[] sorted = am1.array(); + double max = (sorted[n-1] + sorted[n-2])*100.0/((double)n); + return max; + } + + + + + + // DELETION OF AN ITEM + // Delete an item - item name supplied + public double[][] deleteItem(String name){ + int index = this.itemIndex(name); + return this.deleteItem(index); + } + + // Delete an item - index supplied (indices starting at 1 NOT 0) + public double[][] deleteItem(int index){ + index--; + int jj = 0; + + double[][] array1 = new double[this.nItems-1][this.nPersons]; + for(int i=0; i<this.nItems; i++){ + if(i!=index){ + array1[jj] = scores0[i]; + jj++; + } + } + return this.transpose0to1(array1); + } + + + // SCATTER PLOTS + // Plot of item - item responses - raw data + public void rawItemItemPlot(String itemName1, String itemName2){ + int index1 = this.itemIndex(itemName1); + int index2 = this.itemIndex(itemName2); + this.rawItemItemPlot(index1, index2); + } + + + // Plot of item - item responses - raw data + public void rawItemItemPlot(int itemIndex1, int itemIndex2){ + itemIndex1--; + itemIndex2--; + + PlotGraph pg = new PlotGraph(this.scores0[itemIndex1], this.scores0[itemIndex2]); + String graphTitle = "Scores: plot of responses to the item, " + this.itemNames[itemIndex1] + ", against those to the item, " + this.itemNames[itemIndex2]; + pg.setGraphTitle(graphTitle); + pg.setXaxisLegend("Responses to the item, " + this.itemNames[itemIndex1]); + pg.setYaxisLegend("Responses to the item, " + this.itemNames[itemIndex2]); + pg.setLine(0); + pg.setPoint(4); + pg.plot(); + } + + // Plot of item - means responses - raw data + public void rawItemMeansPlot(String itemName){ + int index = this.itemIndex(itemName); + this.rawItemMeansPlot(index); + } + + // Plot of item - means responses - raw data + public void rawItemMeansPlot(int itemIndex){ + itemIndex--; + + PlotGraph pg = new PlotGraph(this.rawPersonMeans, this.scores0[itemIndex]); + String graphTitle = "Scores: plot of responses to the item, " + this.itemNames[itemIndex] + ", against the means of the responses to all items"; + pg.setGraphTitle(graphTitle); + pg.setXaxisLegend("Mean of the responses to all the items, "); + pg.setYaxisLegend("Responses to the item, " + this.itemNames[itemIndex]); + pg.setLine(0); + pg.setPoint(4); + pg.plot(); + } + + + + // Plot of item - item responses - standardized data + public void standardizedItemItemPlot(String itemName1, String itemName2){ + int index1 = this.itemIndex(itemName1); + int index2 = this.itemIndex(itemName2); + this.standardizedItemItemPlot(index1, index2); + } + + public void standardisedItemItemPlot(String itemName1, String itemName2){ + this.standardizedItemItemPlot(itemName1, itemName2); + } + + // Plot of item - item responses - standardized data + public void standardizedItemItemPlot(int itemIndex1, int itemIndex2){ + itemIndex1--; + itemIndex2--; + + PlotGraph pg = new PlotGraph(this.standardizedScores0[itemIndex1], this.standardizedScores0[itemIndex2]); + String graphTitle = "Scores: plot of responses to the item, " + this.itemNames[itemIndex1] + ", against those to the item, " + this.itemNames[itemIndex2]; + pg.setGraphTitle(graphTitle); + pg.setXaxisLegend("Responses to the item, " + this.itemNames[itemIndex1]); + pg.setYaxisLegend("Responses to the item, " + this.itemNames[itemIndex2]); + pg.setLine(0); + pg.setPoint(4); + pg.plot(); + } + + public void standardisedItemItemPlot(int itemIndex1, int itemIndex2){ + this.standardizedItemItemPlot(itemIndex1, itemIndex2); + } + + + // Plot of item - means responses - standardized data + public void standardizedItemMeansPlot(String itemName){ + int index = this.itemIndex(itemName); + this.standardizedItemMeansPlot(index); + } + + public void standardisedItemMeansPlot(String itemName){ + this.standardizedItemMeansPlot(itemName); + } + + + // Plot of item - means responses - standardized data + public void standardizedItemMeansPlot(int itemIndex){ + itemIndex--; + + PlotGraph pg = new PlotGraph(this.standardizedPersonMeans, this.standardizedScores0[itemIndex]); + String graphTitle = "Scores: plot of responses to the item, " + this.itemNames[itemIndex] + ", against the means of the responses to all items"; + pg.setGraphTitle(graphTitle); + pg.setXaxisLegend("Mean of the responses to all the items, "); + pg.setYaxisLegend("Responses to the item, " + this.itemNames[itemIndex]); + pg.setLine(0); + pg.setPoint(4); + pg.plot(); + } + + public void standardisedItemMeansPlot(int itemIndex){ + this.standardizedItemMeansPlot(itemIndex); + } + + // OUTPUT METHODS + + // Set number of decimal places in the output data + // default value = 6 + public void numberOfDecimalPlaces(int trunc){ + this.trunc = trunc; + } + + // Type of output file + // option = 1 - text file (.txt) + // option = 2 - MS Excel readable file (.xls) [default option] + public void setOutputFileType(int option){ + this.fileOption = option; + this.fileOptionSet = true; + } + + // Set numbering of output filename to prevent overwriting + // default value = false + public void setFileNumbering(){ + this.fileNumberingSet = true; + } + + // Remove numbering of output filename thus allowing overwriting + // default value = false + public void removeFileNumbering(){ + this.fileNumberingSet = false; + } + + // CONVERSIONS + // Convert to PCA + public PCA toPCA(){ + PCA pca = new PCA(); + + pca.title = this.title; + pca.titleLines = this.titleLines; + pca.inputFilename = this.inputFilename; + pca.outputFilename = this.outputFilename; + pca.fileOption = this.fileOption; + pca.fileOptionSet = this.fileOptionSet; + pca.fileExtensions = this.fileExtensions; + pca.fileNumberingSet = this.fileNumberingSet; + + pca.originalDataType = this.originalDataType; // - String[][] (including read from file); + pca.originalDataOrder = this.originalDataOrder; // - matrix columns = responses of a person + pca.originalData = this.originalData; // Original data as entered + pca.scores0 = this.scores0.clone(); // individual scores - after any 'no response' deletions or replacements + pca.originalScores0 = this.originalScores0.clone(); // scores0 before any 'no response' deletions or replacements + pca.standardizedScores0 = this.standardizedScores0.clone(); // standardized scores0 + pca.scores1 = this.scores1.clone(); // individual scores - after any 'no response' deletions or replacements + pca.originalScores1 = this.originalScores1.clone(); // scores1 before any 'no response' deletions or replacements + pca.standardizedScores1 = this.standardizedScores1.clone(); // standardized scores1 + pca.dataEntered = this.dataEntered; // = true when scores entered + pca.nItems = this.nItems; // number of items, after any deletions + pca.originalNitems = this.originalNitems; // original number of items + pca.itemNames = this.itemNames.clone(); // names of the items + pca.originalItemNames = this.originalItemNames.clone(); // list of item names before any deletions + pca.itemNamesSet = this.itemNamesSet; // = true when item names entered + pca.nPersons = this.nPersons; // number of persons, after any deletions + pca.originalNpersons = this.originalNpersons; // original number of persons + pca.nScores = this.nScores; + pca.originalNscores = this.originalNscores; // original total number of scores + pca.otherFalse = this.otherFalse; // false value for dichotomous data if one of the default values + pca.otherTrue = this.otherTrue; // true value for dichotomous data if one of the default values + pca.otherDichotomousDataSet = this.otherDichotomousDataSet; // = true if user sets an alternative dichotomous pair + pca.dichotomous = this.dichotomous.clone(); // true if the data in an item is dichotomous + pca.dichotomousPercentage = this.dichotomousPercentage.clone(); // percentage of responses in an item that are dichotomous + pca.dichotomousOverall = this.dichotomousOverall; // true if all the data is dichotomous + pca.dichotomousCheckDone = this.dichotomousCheckDone; // true if check for dichotomous data performed + pca.letterToNumeralSet = this.letterToNumeralSet; // = true if user set the letter to numeral option allowing alphabetic response input + pca.ignoreNoResponseRequests = this.ignoreNoResponseRequests; // = true - requests for 'no resonse' options are not displayed + pca.itemDeletionPercentage = this.itemDeletionPercentage; // percentage of no responses allowed within an item before the item is deleted + pca.itemDeletionPercentageSet = this.itemDeletionPercentageSet; // = true when this percentage is reset + pca.personDeletionPercentage = this.personDeletionPercentage; // percentage of no responses allowed within a person's responses before the person is deleted + pca.personDeletionPercentageSet = this.personDeletionPercentageSet; // = true when this percentage is reset + pca.replacementOption = this.replacementOption; // option flag for a missing response if deletion not carried out + pca.replacementOptionNames = this.replacementOptionNames.clone(); + pca.replacementOptionSet = this.replacementOptionSet; // = true when replacementOption set + pca.allNoResponseOptionsSet = this.allNoResponseOptionsSet; // = true when personDeletionPercentageSet, itemDeletionPercentageSet and replacementOptionSet are all true + + pca.noResponseHandlingSet = this.noResponseHandlingSet; // = true when 'no response' handling options are all set + pca.nNaN = this.nNaN; // number of 'no responses' (initially equated to NaN) + pca.deletedItems = this.deletedItems.clone(); // = true if item corresponding to the deletedItems array index has been deleted, false otherwise + pca.nDeletedItems = this.nDeletedItems; // number of deleted items + pca.deletedItemsIndices = this.deletedItemsIndices.clone(); // indices of the deleted items + pca.itemIndices = this.itemIndices.clone(); // indices of items in original data before deletions + pca.deletedPersons = this.deletedPersons.clone(); // = true if person corresponding to the deletedItems array index has been deleted, false otherwise // person deleted if no response in all items,then deleted irrespective of missing response option choice + pca.nDeletedPersons = this.nDeletedPersons; // number of deleted persons + pca.deletedPersonsIndices = this.deletedPersonsIndices.clone(); // indices of the deleted persons + pca.personIndices = this.personIndices.clone(); // indices of persons in original data before deletions + pca.nReplacements = this.nReplacements; // number of 'no response' replacements + pca.replacementIndices = replacementIndices.clone(); // indices of 'no response' replacements + + pca.nFactorOption = this.nFactorOption; + if(this.dataEntered){ + pca.dataPreprocessed = false; // = true when scores have been preprocessed + pca.preprocessData(); + } + + return pca; + } + + // Convert to Cronbach + public Cronbach toCronbach(){ + Cronbach cr = new Cronbach(); + + cr.title = this.title; + cr.titleLines = this.titleLines; + cr.inputFilename = this.inputFilename; + cr.outputFilename = this.outputFilename; + cr.fileOption = this.fileOption; + cr.fileOptionSet = this.fileOptionSet; + cr.fileExtensions = this.fileExtensions; + cr.fileNumberingSet = this.fileNumberingSet; + + cr.originalDataType = this.originalDataType; // - String[][] (including read from file); + cr.originalDataOrder = this.originalDataOrder; // - matrix columns = responses of a person + cr.originalData = this.originalData; // Original data as entered + cr.scores0 = this.scores0.clone(); // individual scores - after any 'no response' deletions or replacements + cr.originalScores0 = this.originalScores0.clone(); // scores0 before any 'no response' deletions or replacements + cr.standardizedScores0 = this.standardizedScores0.clone(); // standardized scores0 + cr.scores1 = this.scores1.clone(); // individual scores - after any 'no response' deletions or replacements + cr.originalScores1 = this.originalScores1.clone(); // scores1 before any 'no response' deletions or replacements + cr.standardizedScores1 = this.standardizedScores1.clone(); // standardized scores1 + cr.dataEntered = this.dataEntered; // = true when scores entered + cr.nItems = this.nItems; // number of items, after any deletions + cr.originalNitems = this.originalNitems; // original number of items + cr.itemNames = this.itemNames.clone(); // names of the items + cr.originalItemNames = this.originalItemNames.clone(); // list of item names before any deletions + cr.itemNamesSet = this.itemNamesSet; // = true when item names entered + cr.nPersons = this.nPersons; // number of persons, after any deletions + cr.originalNpersons = this.originalNpersons; // original number of persons + cr.nScores = this.nScores; + cr.originalNscores = this.originalNscores; // original total number of scores + cr.otherFalse = this.otherFalse; // false value for dichotomous data if one of the default values + cr.otherTrue = this.otherTrue; // true value for dichotomous data if one of the default values + cr.otherDichotomousDataSet = this.otherDichotomousDataSet; // = true if user sets an alternative dichotomous pair + cr.dichotomous = this.dichotomous.clone(); // true if the data in an item is dichotomous + cr.dichotomousPercentage = this.dichotomousPercentage.clone(); // percentage of responses in an item that are dichotomous + cr.dichotomousOverall = this.dichotomousOverall; // true if all the data is dichotomous + cr.dichotomousCheckDone = this.dichotomousCheckDone; // true if check for dichotomous data performed + cr.letterToNumeralSet = this.letterToNumeralSet; // = true if user set the letter to numeral option allowing alphabetic response input + cr.ignoreNoResponseRequests = this.ignoreNoResponseRequests; // = true - requests for 'no resonse' options are not displayed + cr.itemDeletionPercentage = this.itemDeletionPercentage; // percentage of no responses allowed within an item before the item is deleted + cr.itemDeletionPercentageSet = this.itemDeletionPercentageSet; // = true when this percentage is reset + cr.personDeletionPercentage = this.personDeletionPercentage; // percentage of no responses allowed within a person's responses before the person is deleted + cr.personDeletionPercentageSet = this.personDeletionPercentageSet; // = true when this percentage is reset + cr.replacementOption = this.replacementOption; // option flag for a missing response if deletion not carried out + cr.replacementOptionNames = this.replacementOptionNames.clone(); + cr.replacementOptionSet = this.replacementOptionSet; // = true when replacementOption set + cr.allNoResponseOptionsSet = this.allNoResponseOptionsSet; // = true when personDeletionPercentageSet, itemDeletionPercentageSet and replacementOptionSet are all true + + cr.noResponseHandlingSet = this.noResponseHandlingSet; // = true when 'no response' handling options are all set + cr.nNaN = this.nNaN; // number of 'no responses' (initially equated to NaN) + cr.deletedItems = this.deletedItems.clone(); // = true if item corresponding to the deletedItems array index has been deleted, false otherwise + cr.nDeletedItems = this.nDeletedItems; // number of deleted items + cr.deletedItemsIndices = this.deletedItemsIndices.clone(); // indices of the deleted items + cr.itemIndices = this.itemIndices.clone(); // indices of items in original data before deletions + cr.deletedPersons = this.deletedPersons.clone(); // = true if person corresponding to the deletedItems array index has been deleted, false otherwise // person deleted if no response in all items,then deleted irrespective of missing response option choice + cr.nDeletedPersons = this.nDeletedPersons; // number of deleted persons + cr.deletedPersonsIndices = this.deletedPersonsIndices.clone(); // indices of the deleted persons + cr.personIndices = this.personIndices.clone(); // indices of persons in original data before deletions + cr.nReplacements = this.nReplacements; // number of 'no response' replacements + cr.replacementIndices = replacementIndices.clone(); // indices of 'no response' replacements + + cr.nFactorOption = this.nFactorOption; + if(this.dataEntered){ + cr.dataPreprocessed = false; // = true when scores have been preprocessed + cr.preprocessData(); + } + + return cr; + } +} + + + + + + + diff --git a/src/main/java/flanagan/analysis/Stat.java b/src/main/java/flanagan/analysis/Stat.java new file mode 100755 index 0000000000000000000000000000000000000000..0b6fe23f023ccb1e4ab930b1403b54ec501afe07 --- /dev/null +++ b/src/main/java/flanagan/analysis/Stat.java @@ -0,0 +1,13540 @@ +/* +* Class Stat +* +* USAGE: Statistical functions +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: June 2002 as part of Fmath +* AMENDED: 12 May 2003 Statistics separated out from Fmath as a new class +* DATE: 18 June 2005, 5 January 2006, 25 April 2006, 12, 21 November 2006 +* 4 December 2006 (renaming of cfd and pdf methods - older version also retained) +* 31 December 2006, March 2007, 14 April 2007, 19 October 2007, 27 February 2008 +* 29 March 2008, 7 April 2008, 29 April 2008 - 13 May 2008, 22-31 May 2008, +* 4-10 June 2008, 27 June 2008, 2-5 July 2008, 23 July 2008, 31 July 2008, +* 2-4 August 2008, 20 August 2008, 5-10 September 2008, 19 September 2008, +* 28-30 September 2008 (probability Plot moved to separate class, ProbabilityPlot) +* 4-5 October 2008, 8-13 December 2008, 14 June 2009, 13-23 October 2009 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Stat.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, ++ this list of conditions and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission +* from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.analysis; + +import java.util.*; +import java.math.*; + +import flanagan.math.*; +import flanagan.integration.Integration; +import flanagan.integration.IntegralFunction; + +import flanagan.plot.PlotGraph; +import flanagan.complex.*; +import flanagan.circuits.Phasor; +import flanagan.roots.*; +import flanagan.io.*; + + +public class Stat extends ArrayMaths{ + + // INSTANCE VARIABLES + private boolean nFactorOptionI = false; // = true varaiance, covariance and standard deviation denominator = n + // = false varaiance, covariance and standard deviation denominator = n-1 + private boolean nFactorReset = false; // = true when instance method resetting the denominator is called + + private boolean nEffOptionI = true; // = true n replaced by effective sample number + // = false n used as sample number + private boolean nEffReset = false; // = true when instance method resetting the nEff choice called + + private boolean weightingOptionI = true; // = true 'little w' weights (uncertainties) used + // = false 'big W' weights (multiplicative factors) used + private boolean weightingReset = false; // = true when instance method resetting the nEff choice called + + private ArrayMaths amWeights = null; // weights as ArrayMaths + private boolean weightsSupplied = false; // = true if weights entered + + private ArrayList<Object> upperOutlierDetails = new ArrayList<Object>(); // upper outlier search details + // element 0 - number of ouliers (Integer) + // element 1 - outliers (double[]) + // element 2 - outlier indices (inmoved + private boolean upperDone = false; // = true when upper oulier search ct[]) + // element 3 - array with ouliers reompleted even if no upper outliers found + private ArrayList<Object> lowerOutlierDetails = new ArrayList<Object>(); // lower outlier search details + // element 0 - number of ouliers (Integer) + // element 1 - outliers (double[]) + // element 2 - outlier indices (int[]) + // element 3 - array with ouliers removed + private boolean lowerDone = false; // = true when lower oulier search completed even if no upper outliers found + + + // STATIC VARIABLES + private static boolean nFactorOptionS = false; // = true varaiance, covariance and standard deviation denominator = n + // = false varaiance and standard deviation denominator = n-1 + private static boolean nEffOptionS = true; // = true n replaced by effective sample number + // = false n used as sample number + + private static boolean weightingOptionS= true; // = true 'little w' weights (uncertainties) used + // = false 'big W' weights (multiplicative factors) used + + // A small number close to the smallest representable floating point number + public static final double FPMIN = 1e-300; + + // PRIVATE MEMBERS FOR USE IN GAMMA FUNCTION METHODS AND HISTOGRAM CONSTRUCTION METHODS + + // GAMMA FUNCTIONS + // Lanczos Gamma Function approximation - N (number of coefficients -1) + private static int lgfN = 6; + // Lanczos Gamma Function approximation - Coefficients + private static double[] lgfCoeff = {1.000000000190015, 76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179E-2, -0.5395239384953E-5}; + // Lanczos Gamma Function approximation - small gamma + private static double lgfGamma = 5.0; + // Maximum number of iterations allowed in Incomplete Gamma Function calculations + private static int igfiter = 1000; + // Tolerance used in terminating series in Incomplete Gamma Function calculations + private static double igfeps = 1e-8; + + // HISTOGRAM CONSTRUCTION + // Tolerance used in including an upper point in last histogram bin when it is outside due to rounding erors + private static double histTol = 1.0001D; + + // CONSTRUCTORS + public Stat(){ + super(); + } + + public Stat(double[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(Double[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(float[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(Float[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(long[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(Long[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(int[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(Integer[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(short[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(Short[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(byte[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(Byte[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(BigDecimal[] xx){ + super(xx); + } + + public Stat(BigInteger[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(Complex[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(Phasor[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(String[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(Object[] xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(Vector<Object> xx){ + super(xx); + this.convertToHighest(); + } + + public Stat(ArrayList<Object> xx){ + super(xx); + this.convertToHighest(); + } + + // Convert array to Double if not Complex, Phasor, BigDecimal or BigInteger + // Convert to BigDecimal if BigInteger + // Convert Phasor to Complex + public void convertToHighest(){ + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: + case 18: Double[] dd = this.getArray_as_Double(); + this.array.clear(); + for(int i=0; i<this.length; i++)this.array.add(dd[i]); + double[] ww = new double[this.length]; + for(int i=0; i<this.length; i++)ww[i]=1.0D; + amWeights = new ArrayMaths(ww); + this.type = 1; + break; + case 12: + case 13: BigDecimal[] bd = this.getArray_as_BigDecimal(); + this.array.clear(); + for(int i=0; i<this.length; i++)this.array.add(bd[i]); + BigDecimal[] wd = new BigDecimal[this.length]; + for(int i=0; i<this.length; i++)wd[i]=BigDecimal.ONE; + amWeights = new ArrayMaths(wd); + this.type = 12; + bd = null; + break; + case 14: + case 15: Complex[] cc = this.getArray_as_Complex(); + this.array.clear(); + for(int i=0; i<this.length; i++)this.array.add(cc[i]); + Complex[] wc = new Complex[this.length]; + for(int i=0; i<this.length; i++)wc[i]=Complex.plusOne(); + amWeights = new ArrayMaths(wc); + this.type = 14; + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + } + + + // INSTANCE METHODS + // Set weights to 'big W' - multiplicative factor + public void setWeightsToBigW(){ + this.weightingOptionI = false; + this.weightingReset = true; + } + + // Set weights to 'little w' - uncertainties + public void setWeightsToLittleW(){ + this.weightingOptionI = true; + this.weightingReset = true; + } + + // Set standard deviation, variance and covariance denominators to n + public void setDenominatorToN(){ + this.nFactorOptionI = true; + this.nFactorReset = true; + } + + // Set standard deviation, variance and covariance denominators to n-1 + public void setDenominatorToNminusOne(){ + this.nFactorOptionI = false; + this.nFactorReset = true; + } + + // Repalce number of data points to the effective sample number in weighted calculations + public void useEffectiveN(){ + this.nEffOptionI = true; + this.nEffReset = true; + } + + // Repalce the effective sample number in weighted calculations by the number of data points + public void useTrueN(){ + this.nEffOptionI = false; + this.nEffReset = true; + } + + // Return the effective sample number + public double effectiveSampleNumber(){ + return this.effectiveSampleNumber_as_double(); + + } + + public double effectiveSampleNumber_as_double(){ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double nEff = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + nEff = Stat.effectiveSampleNumber(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + nEff = Stat.effectiveSampleNumber(bd).doubleValue(); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return nEff; + } + + public BigDecimal effectiveSampleNumber_as_BigDecimal(){ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + BigDecimal nEff = BigDecimal.ZERO; + switch(this.type){ + case 1: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + nEff = Stat.effectiveSampleNumber(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to BigDecimal"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return nEff; + } + + public Complex effectiveSampleNumber_as_Complex(){ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + Complex nEff = Complex.zero(); + switch(this.type){ + case 1: + case 12: + case 14: Complex[] cc = this.getArray_as_Complex(); + nEff = Stat.effectiveSampleNumber(cc); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return nEff; + } + + // Return the true sample number + public int trueSampleNumber(){ + return this.length; + + } + + public int trueSampleNumber_as_int(){ + return this.length; + } + + public double trueSampleNumber_as_double(){ + return (double)this.length; + } + + public BigDecimal trueSampleNumber_as_BigDecimal(){ + return new BigDecimal(new Integer(this.length).toString()); + } + + public Complex trueSampleNumber_as_Complex(){ + return new Complex((double)this.length, 0.0); + } + + + // CONVERSION OF WEIGHTING FACTORS (INSTANCE) + // Converts weighting facors Wi to wi, i.e. to 1/sqrt(Wi) + // DEPRECATED !!! + public void convertBigWtoLittleW(){ + if(!this.weightsSupplied){ + System.out.println("convertBigWtoLittleW: no weights have been supplied - all weights set to unity"); + } + else{ + amWeights = amWeights.oneOverSqrt(); + } + } + + // ENTER AN ARRAY OF WEIGHTS + public void setWeights(double[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(Double[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(float[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(Float[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(long[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(Long[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(int[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(Integer[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(short[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(Short[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(byte[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(Byte[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(BigDecimal[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(BigInteger[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(Complex[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(Phasor[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(Object[] xx){ + if(this.length!=xx.length)throw new IllegalArgumentException("Length of weights array, " + xx.length + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(Vector<Object> xx){ + if(this.length!=xx.size())throw new IllegalArgumentException("Length of weights array, " + xx.size() + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + public void setWeights(ArrayList<Object> xx){ + if(this.length!=xx.size())throw new IllegalArgumentException("Length of weights array, " + xx.size() + ", must be the same as the length of the instance internal array, " + this.length); + ArrayMaths wm = new ArrayMaths(xx); + this.convertWeights(wm); + this.weightsSupplied = true; + } + + private void convertWeights(ArrayMaths wm){ + switch(this.type){ + case 1: switch(wm.typeIndex()){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: Double[] w1 = wm.getArray_as_Double(); + this.amWeights = new ArrayMaths(w1); + break; + case 12: + case 13: BigDecimal[] a2 = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)this.array.add(a2[i]); + BigDecimal[] w2 = wm.getArray_as_BigDecimal(); + this.amWeights = new ArrayMaths(w2); + a2 = null; + w2 = null; + break; + case 14: + case 15: Complex[] a3 = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)this.array.add(a3[i]); + Complex[] w3 = wm.getArray_as_Complex(); + this.amWeights = new ArrayMaths(w3); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + + } + break; + case 12: switch(wm.typeIndex()){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: BigDecimal[] w4 = wm.getArray_as_BigDecimal(); + this.amWeights = new ArrayMaths(w4); + w4 = null; + break; + case 12: + case 13: BigDecimal[] w5 = wm.getArray_as_BigDecimal(); + this.amWeights = new ArrayMaths(w5); + w5 = null; + break; + case 14: + case 15: Complex[] a6 = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)this.array.add(a6[i]); + Complex[] w6 = wm.getArray_as_Complex(); + this.amWeights = new ArrayMaths(w6); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + break; + case 14: Complex[] a7 = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)this.array.add(a7[i]); + Complex[] w7 = wm.getArray_as_Complex(); + this.amWeights = new ArrayMaths(w7); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + } + + // ARITMETIC MEANS (INSTANCE) + public double mean(){ + return this.mean_as_double(); + + } + + public double mean_as_double(){ + double mean = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++){ + mean += dd[i]; + } + mean /= (double)this.length; + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal meanbd = BigDecimal.ZERO; + for(int i=0; i<this.length; i++)meanbd = meanbd.add(bd[i]); + meanbd = meanbd.divide(new BigDecimal((double)this.length), BigDecimal.ROUND_HALF_UP); + mean = meanbd.doubleValue(); + bd = null; + meanbd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + } + + public BigDecimal mean_as_BigDecimal(){ + BigDecimal mean = BigDecimal.ZERO; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + double meand= 0.0D; + for(int i=0; i<this.length; i++)meand += dd[i]; + meand /= (double)this.length; + mean = new BigDecimal(meand); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)mean = mean.add(bd[i]); + mean = mean.divide(new BigDecimal((double)this.length), BigDecimal.ROUND_HALF_UP); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to BigDecimal"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + } + + public Complex mean_as_Complex(){ + Complex mean = Complex.zero(); + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + double meand= 0.0D; + for(int i=0; i<this.length; i++)meand += dd[i]; + meand /= (double)this.length; + mean = new Complex(meand); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal meanbd = BigDecimal.ZERO; + for(int i=0; i<this.length; i++)meanbd = meanbd.add(bd[i]); + meanbd = meanbd.divide(new BigDecimal((double)this.length), BigDecimal.ROUND_HALF_UP); + mean = new Complex(meanbd.doubleValue()); + bd = null; + meanbd = null; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)mean = mean.plus(cc[i]); + mean = mean.over(new Complex((double)this.length)); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + } + + + // WEIGHTED ARITMETIC MEANS (INSTANCE) + public double weightedMean(){ + return this.weightedMean_as_double(); + } + + public double weightedMean_as_double(){ + if(!this.weightsSupplied){ + System.out.println("weightedMean_as_double: no weights supplied - unweighted mean returned"); + return this.mean_as_double(); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double mean = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + double[] wwd = this.amWeights.getArray_as_double(); + mean = Stat.mean(dd, wwd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wwb = this.amWeights.getArray_as_BigDecimal(); + mean = (Stat.mean(bd, wwb)).doubleValue(); + bd = null; + wwb = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return mean; + } + } + + public BigDecimal weightedMean_as_BigDecimal(){ + if(!this.weightsSupplied){ + System.out.println("weightedMean_as_BigDecimal: no weights supplied - unweighted mean returned"); + return this.mean_as_BigDecimal(); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + BigDecimal mean = BigDecimal.ZERO; + switch(this.type){ + case 1: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wwb = this.amWeights.getArray_as_BigDecimal(); + mean = Stat.mean(bd, wwb); + bd = null; + wwb = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to BigDecimal"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return mean; + } + } + + public Complex weightedMean_as_Complex(){ + if(!this.weightsSupplied){ + System.out.println("weightedMean_as_Complex: no weights supplied - unweighted mean returned"); + return this.mean_as_Complex(); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + Complex mean = Complex.zero(); + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + double[] wwd = this.amWeights.getArray_as_double(); + mean = new Complex(Stat.mean(dd, wwd)); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wwb = this.amWeights.getArray_as_BigDecimal(); + mean = new Complex((Stat.mean(bd, wwb)).doubleValue()); + bd = null; + wwb = null; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + Complex[] wwc = this.amWeights.getArray_as_Complex(); + mean = Stat.mean(cc, wwc); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return mean; + } + } + + // SUBTRACT AN ARITMETIC MEAN FROM AN ARRAY (INSTANCE) + public double[] subtractMean(){ + return this.subtractMean_as_double(); + } + + public double[] subtractMean_as_double(){ + double[] arrayminus = new double[this.length]; + switch(this.type){ + case 1: double meand = this.mean_as_double(); + ArrayMaths amd = this.minus(meand); + arrayminus = amd.getArray_as_double(); + break; + case 12: BigDecimal meanb = this.mean_as_BigDecimal(); + ArrayMaths amb = this.minus(meanb); + arrayminus = amb.getArray_as_double(); + meanb = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return arrayminus; + } + + public BigDecimal[] subtractMean_as_BigDecimal(){ + BigDecimal[] arrayminus = new BigDecimal[this.length]; + switch(this.type){ + case 1: + case 12: BigDecimal meanb = this.mean_as_BigDecimal(); + ArrayMaths amb = this.minus(meanb); + arrayminus = amb.getArray_as_BigDecimal(); + meanb = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to BigDecimal"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return arrayminus; + } + + public Complex[] subtractMean_as_Complex(){ + Complex[] arrayminus = new Complex[this.length]; + switch(this.type){ + case 1: double meand = this.mean_as_double(); + ArrayMaths amd = this.minus(meand); + arrayminus = amd.getArray_as_Complex(); + break; + case 12: BigDecimal meanb = this.mean_as_BigDecimal(); + ArrayMaths amb = this.minus(meanb); + arrayminus = amb.getArray_as_Complex(); + meanb = null; + break; + case 14: Complex meanc = this.mean_as_Complex(); + ArrayMaths amc = this.minus(meanc); + arrayminus = amc.getArray_as_Complex(); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return arrayminus; + } + + // SUBTRACT AN WEIGHTED ARITMETIC MEAN FROM AN ARRAY (INSTANCE) + public double[] subtractWeightedMean(){ + return this.subtractWeightedMean_as_double(); + } + + public double[] subtractWeightedMean_as_double(){ + if(!this.weightsSupplied){ + System.out.println("subtractWeightedMean_as_double: no weights supplied - unweighted values returned"); + return this.subtractMean_as_double(); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double[] arrayminus = new double[this.length]; + switch(this.type){ + case 1: double meand = this.weightedMean_as_double(); + ArrayMaths amd = this.minus(meand); + arrayminus = amd.getArray_as_double(); + break; + case 12: BigDecimal meanb = this.weightedMean_as_BigDecimal(); + ArrayMaths amb = this.minus(meanb); + arrayminus = amb.getArray_as_double(); + meanb = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return arrayminus; + } + } + + public BigDecimal[] subtractWeightedMean_as_BigDecimal(){ + if(!this.weightsSupplied){ + System.out.println("subtractWeightedMean_as_BigDecimal: no weights supplied - unweighted values returned"); + return this.subtractMean_as_BigDecimal(); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + BigDecimal[] arrayminus = new BigDecimal[this.length]; + switch(this.type){ + case 1: + case 12: BigDecimal meanb = this.weightedMean_as_BigDecimal(); + ArrayMaths amb = this.minus(meanb); + arrayminus = amb.getArray_as_BigDecimal(); + meanb = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to BigDecimal"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return arrayminus; + } + } + + public Complex[] subtractWeightedMean_as_Complex(){ + if(!this.weightsSupplied){ + System.out.println("subtractWeightedMean_as_Complex: no weights supplied - unweighted values returned"); + return this.subtractMean_as_Complex(); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + Complex[] arrayminus = new Complex[this.length]; + switch(this.type){ + case 1: double meand = this.weightedMean_as_double(); + ArrayMaths amd = this.minus(meand); + arrayminus = amd.getArray_as_Complex(); + break; + case 12: BigDecimal meanb = this.weightedMean_as_BigDecimal(); + ArrayMaths amb = this.minus(meanb); + arrayminus = amb.getArray_as_Complex(); + meanb = null; + break; + case 14: Complex meanc = this.weightedMean_as_Complex(); + ArrayMaths amc = this.minus(meanc); + arrayminus = amc.getArray_as_Complex(); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return arrayminus; + } + } + + + // GEOMETRIC MEAN(INSTANCE) + public double geometricMean(){ + return this.geometricMean_as_double(); + } + + public double geometricMean_as_double(){ + double gmean = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + gmean = Stat.geometricMean(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + gmean = Stat.geometricMean(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + + } + return gmean; + } + + public Complex geometricMean_as_Complex(){ + Complex gmean = Complex.zero(); + switch(this.type){ + case 1: + case 12: + case 14: Complex[] cc = this.getArray_as_Complex(); + gmean = Stat.geometricMean(cc); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return gmean; + } + + + // WEIGHTED GEOMETRIC MEAN(INSTANCE) + public double weightedGeometricMean(){ + return this.weightedGeometricMean_as_double(); + } + + public double weightedGeometricMean_as_double(){ + if(!this.weightsSupplied){ + System.out.println("weightedGeometricMean_as_double: no weights supplied - unweighted value returned"); + return this.geometricMean_as_double(); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double gmean = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + double[] ww = this.getArray_as_double(); + gmean = Stat.geometricMean(dd, ww); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wd = this.getArray_as_BigDecimal(); + gmean = Stat.geometricMean(bd, wd); + bd = null; + wd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + + } + Stat.weightingOptionS = holdW; + return gmean; + } + } + + public Complex weightedGeometricMean_as_Complex(){ + if(!this.weightsSupplied){ + System.out.println("weightedGeometricMean_as_Complex: no weights supplied - unweighted value returned"); + return this.geometricMean_as_Complex(); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + Complex gmean = Complex.zero(); + switch(this.type){ + case 1: + case 12: + case 14: Complex[] cc = this.getArray_as_Complex(); + Complex[] ww = this.getArray_as_Complex(); + gmean = Stat.geometricMean(cc, ww); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return gmean; + } + } + + // HARMONIC MEANS (INSTANCE) + public double harmonicMean(){ + return this.harmonicMean_as_double(); + } + + public double harmonicMean_as_double(){ + + double mean = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + mean = Stat.harmonicMean(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + mean = (Stat.harmonicMean(bd)).doubleValue(); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + + } + + public BigDecimal harmonicMean_as_BigDecimal(){ + + BigDecimal mean = BigDecimal.ZERO; + switch(this.type){ + case 1: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + mean = Stat.harmonicMean(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to BigDecimal"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + + } + + public Complex harmonicMean_as_Complex(){ + + Complex mean = Complex.zero(); + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + mean = new Complex(Stat.harmonicMean(dd)); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + mean = new Complex((Stat.harmonicMean(bd)).doubleValue()); + bd = null; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + mean = Stat.harmonicMean(cc); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + + } + + // WEIGHTED HARMONIC MEANS (INSTANCE) + public double weightedHarmonicMean(){ + return this.weightedHarmonicMean_as_double(); + } + + public double weightedHarmonicMean_as_double(){ + if(!this.weightsSupplied){ + System.out.println("weightedHarmonicMean_as_double: no weights supplied - unweighted mean returned"); + return this.harmonicMean_as_double(); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double mean = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + double[] wwd = this.amWeights.getArray_as_double(); + mean = Stat.harmonicMean(dd, wwd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wwb = this.amWeights.getArray_as_BigDecimal(); + mean = (Stat.harmonicMean(bd, wwb)).doubleValue(); + bd = null; + wwb = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return mean; + } + } + + public BigDecimal weightedHarmonicMean_as_BigDecimal(){ + if(!this.weightsSupplied){ + System.out.println("weightedHarmonicMean_as_BigDecimal: no weights supplied - unweighted mean returned"); + return this.harmonicMean_as_BigDecimal(); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + BigDecimal mean = BigDecimal.ZERO; + switch(this.type){ + case 1: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wwb = this.amWeights.getArray_as_BigDecimal(); + mean = Stat.harmonicMean(bd, wwb); + bd = null; + wwb = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to BigDecimal"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return mean; + } + } + + public Complex weightedHarmonicMean_as_Complex(){ + if(!this.weightsSupplied){ + System.out.println("weightedHarmonicMean_as_Complex: no weights supplied - unweighted mean returned"); + return this.harmonicMean_as_Complex(); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + Complex mean = Complex.zero(); + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + double[] wwd = this.amWeights.getArray_as_double(); + mean = new Complex(Stat.harmonicMean(dd, wwd)); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wwb = this.amWeights.getArray_as_BigDecimal(); + mean = new Complex((Stat.harmonicMean(bd, wwb)).doubleValue()); + bd = null; + wwb = null; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + Complex[] wwc = this.amWeights.getArray_as_Complex(); + mean = Stat.harmonicMean(cc, wwc); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return mean; + } + } + + // GENERALIZED MEANS [POWER MEANS](INSTANCE) + public double generalizedMean(double m){ + return this.generalizedMean_as_double(m); + } + + public double generalizedMean_as_double(double m){ + double mean = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + mean = Stat.generalizedMean(dd, m); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + mean = Stat.generalizedMean(bd, m); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + + } + + public double generalizedMean(BigDecimal m){ + return this.generalizedMean_as_double(m); + } + + public double generalizedMean_as_double(BigDecimal m){ + double mean = 0.0D; + switch(this.type){ + case 1: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + mean = Stat.generalizedMean(bd, m); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to BigDecimal"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + } + + public Complex generalizedMean_as_Complex(double m){ + Complex mean = Complex.zero(); + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + mean = new Complex(Stat.generalizedMean(dd, m)); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + mean = new Complex(Stat.generalizedMean(bd, m)); + bd = null; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + mean = Stat.generalizedMean(cc, m); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + } + + public Complex generalizedMean_as_Complex(Complex m){ + Complex mean = Complex.zero(); + switch(this.type){ + case 1: + case 12: + case 14: Complex[] cc = this.getArray_as_Complex(); + mean = Stat.generalizedMean(cc, m); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + } + + public double generalisedMean(double m){ + return this.generalisedMean_as_double(m); + } + + public double generalisedMean_as_double(double m){ + double mean = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + mean = Stat.generalisedMean(dd, m); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + mean = Stat.generalisedMean(bd, m); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + } + + public double generalisedMean(BigDecimal m){ + return this.generalisedMean_as_double(m); + } + + public double generalisedMean_as_double(BigDecimal m){ + double mean = 0.0D; + switch(this.type){ + case 1: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + mean = Stat.generalisedMean(bd, m); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to BigDecimal"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + } + + public Complex generalisedMean_as_Complex(double m){ + Complex mean = Complex.zero(); + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + mean = new Complex(Stat.generalisedMean(dd, m)); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + mean = new Complex(Stat.generalisedMean(bd, m)); + bd = null; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + mean = Stat.generalisedMean(cc, m); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + } + + public Complex generalisedMean_as_Complex(Complex m){ + Complex mean = Complex.zero(); + switch(this.type){ + case 1: + case 12: + case 14: Complex[] cc = this.getArray_as_Complex(); + mean = Stat.generalisedMean(cc, m); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + } + + + // WEIGHTED GENERALIZED MEANS [WEIGHTED POWER MEANS](INSTANCE) + public double weightedGeneralizedMean(double m){ + return this.weightedGeneralizedMean_as_double(m); + } + + public double weightedGeneralizedMean_as_double(double m){ + if(!this.weightsSupplied){ + System.out.println("weightedGeneralizedMean_as_double: no weights supplied - unweighted mean returned"); + return this.generalizedMean_as_double(m); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double mean = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + double[] ww = this.amWeights.getArray_as_double(); + mean = Stat.generalisedMean(dd, ww, m); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wd = this.amWeights.getArray_as_BigDecimal(); + mean = Stat.generalisedMean(bd, wd, m); + bd = null; + wd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return mean; + } + } + + public double weightedGeneralizedMean(BigDecimal m){ + return this.weightedGeneralizedMean_as_double(m); + } + + public double weightedGeneralizedMean_as_double(BigDecimal m){ + if(!this.weightsSupplied){ + System.out.println("weightedGeneralizedMean_as_double: no weights supplied - unweighted mean returned"); + return this.generalizedMean_as_double(m); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double mean = 0.0D; + switch(this.type){ + case 1: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wd = this.amWeights.getArray_as_BigDecimal(); + mean = Stat.generalisedMean(bd, wd, m); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to BigDecimal"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return mean; + } + } + + public Complex weightedGeneralizedMean_as_Complex(double m){ + if(!this.weightsSupplied){ + System.out.println("weightedGeneralizedMean_as_Complex: no weights supplied - unweighted mean returned"); + return this.generalizedMean_as_Complex(m); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + Complex mean = Complex.zero(); + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + double[] ww = this.amWeights.getArray_as_double(); + mean = new Complex(Stat.generalisedMean(dd, ww, m)); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wd = this.amWeights.getArray_as_BigDecimal(); + mean = new Complex(Stat.generalisedMean(bd, wd, m)); + bd = null; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + Complex[] cw = this.amWeights.getArray_as_Complex(); + mean = Stat.generalisedMean(cc, cw, m); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return mean; + } + } + + public Complex weightedGeneralizedMean_as_Complex(Complex m){ + Complex mean = Complex.zero(); + if(!this.weightsSupplied){ + System.out.println("weightedGeneralizedMean_as_dComplex: no weights supplied - unweighted mean returned"); + return this.generalizedMean_as_Complex(m); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + switch(this.type){ + case 1: + case 12: + case 14: Complex[] cc = this.getArray_as_Complex(); + Complex[] cw = this.amWeights.getArray_as_Complex(); + mean = Stat.generalisedMean(cc, cw, m); + break; + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return mean; + } + } + + public double weightedGeneralisedMean(double m){ + return this.weightedGeneralizedMean_as_double(m); + } + + public double weightedGeneralisedMean_as_double(double m){ + return this.weightedGeneralizedMean_as_double(m); + } + + public double weightedGeneralisedMean(BigDecimal m){ + return this.weightedGeneralizedMean_as_double(m); + } + + public double weightedGeneralisedMean_as_double(BigDecimal m){ + return this.weightedGeneralizedMean_as_double(m); + } + + public Complex weightedGeneralisedMean_as_Complex(double m){ + return this.weightedGeneralizedMean_as_Complex(m); + } + + public Complex weightedGeneralisedMean_as_Complex(Complex m){ + return this.weightedGeneralizedMean_as_Complex(m); + } + + // INTERQUARTILE MEANS (INSTANCE) + public double interQuartileMean(){ + return this.interQuartileMean_as_double(); + } + + public double interQuartileMean_as_double(){ + double mean = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + mean = Stat.interQuartileMean(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + mean = (Stat.interQuartileMean(bd)).doubleValue(); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex interquartile mean is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + } + + public BigDecimal interQuartileMean_as_BigDecimal(){ + BigDecimal mean = BigDecimal.ZERO; + switch(this.type){ + case 1: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + mean = Stat.interQuartileMean(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex interquartile mean is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return mean; + } + + // MEDIAN VALUE(INSTANCE) + public double median(){ + return this.median_as_double(); + } + + public double median_as_double(){ + double median = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + median = Stat.median(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + median = Stat.median(bd).doubleValue(); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex median value not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return median; + } + + public BigDecimal median_as_BigDecimal(){ + BigDecimal median = BigDecimal.ZERO; + switch(this.type){ + case 1: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + median = Stat.median(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex median value not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return median; + } + + // ROOT MEAN SQUARE (INSTANCE METHODS) + public double rms(){ + double rms = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + rms = Stat.rms(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + rms = Stat.rms(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex root mean square is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return rms; + } + + // WEIGHTED ROOT MEAN SQUARE (INSTANCE METHODS) + public double weightedRms(){ + if(!this.weightsSupplied){ + System.out.println("weightedRms: no weights supplied - unweighted rms returned"); + return this.rms(); + } + else{ + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double rms = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + double[] ww = this.amWeights.getArray_as_double(); + rms = Stat.rms(dd, ww); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wd = this.amWeights.getArray_as_BigDecimal(); + rms = Stat.rms(bd, wd); + bd = null; + wd = null; + break; + case 14: throw new IllegalArgumentException("Complex root mean square is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.weightingOptionS = holdW; + return rms; + } + } + + + + // SKEWNESS (INSTANCE METHODS) + // Moment skewness + public double momentSkewness(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double skewness = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + skewness = Stat.momentSkewness(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + skewness = Stat.momentSkewness(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex skewness is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.nFactorOptionS = hold; + return skewness; + } + + public double momentSkewness_as_double(){ + return this.momentSkewness(); + } + + // Median skewness + public double medianSkewness(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double skewness = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + skewness = Stat.medianSkewness(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + skewness = Stat.medianSkewness(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex skewness is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.nFactorOptionS = hold; + return skewness; + } + + public double medianSkewness_as_double(){ + return this.medianSkewness(); + } + + // quartile skewness as double + public double quartileSkewness(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double skewness = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + skewness = Stat.quartileSkewness(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + skewness = Stat.quartileSkewness(bd).doubleValue(); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex skewness is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.nFactorOptionS = hold; + return skewness; + } + + public double quartileSkewness_as_double(){ + return this.quartileSkewness(); + } + + // quartile skewness as BigDecimal + public BigDecimal quartileSkewness_as_BigDecimal(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + BigDecimal skewness = BigDecimal.ZERO; + switch(this.type){ + case 1: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + skewness = Stat.quartileSkewness(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex skewness is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.nFactorOptionS = hold; + return skewness; + } + + + + // KURTOSIS (INSTANCE METHODS) + public double kurtosis(){ + return this.kurtosis_as_double(); + } + + public double kurtosis_as_double(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double kurtosis = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + kurtosis = Stat.kurtosis(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + kurtosis = (Stat.kurtosis(bd)).doubleValue(); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex kurtosis is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.nFactorOptionS = hold; + return kurtosis; + } + + public double curtosis(){ + return this.kurtosis_as_double(); + } + + public double curtosis_as_double(){ + return this.kurtosis_as_double(); + } + + public double kurtosisExcess(){ + return this.kurtosisExcess_as_double(); + } + + public double excessKurtosis(){ + return this.kurtosisExcess_as_double(); + } + + public double excessCurtosis(){ + return this.kurtosisExcess_as_double(); + } + + public double kurtosisExcess_as_double(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double kurtosis = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + kurtosis = Stat.kurtosisExcess(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + kurtosis = (Stat.kurtosisExcess(bd)).doubleValue(); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex kurtosis is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.nFactorOptionS = hold; + return kurtosis; + } + + public double excessKurtosis_as_double(){ + return kurtosisExcess_as_double(); + } + + + public double curtosisExcess(){ + return this.kurtosisExcess_as_double(); + } + + public double curtosisExcess_as_double(){ + return this.kurtosisExcess_as_double(); + } + + public double excessCurtosis_as_double(){ + return this.kurtosisExcess_as_double(); + } + + public BigDecimal kurtosis_as_BigDecimal(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + BigDecimal kurtosis = BigDecimal.ZERO; + switch(this.type){ + case 1: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + kurtosis = Stat.kurtosis(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex kurtosis is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.nFactorOptionS = hold; + return kurtosis; + } + + public BigDecimal curtosis_as_BigDecimal(){ + return this.kurtosis_as_BigDecimal(); + } + + + public BigDecimal kurtosisExcess_as_BigDecimal(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + BigDecimal kurtosis = BigDecimal.ZERO; + switch(this.type){ + case 1: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + kurtosis = Stat.kurtosisExcess(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex kurtosis is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.nFactorOptionS = hold; + return kurtosis; + } + + public BigDecimal excessKurtosis_as_BigDecimal(){ + return this.kurtosisExcess_as_BigDecimal(); + } + + public BigDecimal curtosisExcess_as_BigDecimal(){ + return this.kurtosisExcess_as_BigDecimal(); + } + + public BigDecimal excessCurtosis_as_BigDecimal(){ + return this.kurtosisExcess_as_BigDecimal(); + } + + + + // VARIANCES (INSTANCE METHODS) + public double variance(){ + return this.variance_as_double(); + } + + public double variance_as_double(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double variance = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + variance = Stat.variance(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + variance = (Stat.variance(bd)).doubleValue(); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.nFactorOptionS = hold; + return variance; + } + + public BigDecimal variance_as_BigDecimal(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + BigDecimal variance = BigDecimal.ZERO; + switch(this.type){ + case 1: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + variance = Stat.variance(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to BigDecimal"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.nFactorOptionS = hold; + return variance; + } + + public Complex variance_as_Complex(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + Complex variance = Complex.zero(); + Complex[] cc = this.getArray_as_Complex(); + variance = Stat.variance(cc); + Stat.nFactorOptionS = hold; + return variance; + } + + public double variance_as_Complex_ConjugateCalcn(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + Complex[] cc = this.getArray_as_Complex(); + double variance = Stat.varianceConjugateCalcn(cc); + Stat.nFactorOptionS = hold; + return variance; + } + + public double variance_of_ComplexModuli(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double[] re = this.array_as_modulus_of_Complex(); + double variance = Stat.variance(re); + Stat.nFactorOptionS = hold; + return variance; + } + + public double variance_of_ComplexRealParts(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double[] re = this.array_as_real_part_of_Complex(); + double variance = Stat.variance(re); + Stat.nFactorOptionS = hold; + return variance; + } + + public double variance_of_ComplexImaginaryParts(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double[] im = this.array_as_imaginary_part_of_Complex(); + double variance = Stat.variance(im); + Stat.nFactorOptionS = hold; + return variance; + } + + // WEIGHTED VARIANCES (INSTANCE METHODS) + public double weightedVariance(){ + return this.weightedVariance_as_double(); + } + + public double weightedVariance_as_double(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + + double varr = Double.NaN; + if(!this.weightsSupplied){ + System.out.println("weightedVariance_as_double: no weights supplied - unweighted value returned"); + varr = this.variance_as_double(); + } + else{ + double weightedVariance = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + double[] ww = amWeights.getArray_as_double(); + weightedVariance = Stat.variance(dd, ww); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wd = amWeights.getArray_as_BigDecimal(); + weightedVariance = (Stat.variance(bd, wd)).doubleValue(); + bd = null; + wd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + varr = weightedVariance; + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + return varr; + + } + + public BigDecimal weightedVariance_as_BigDecimal(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + BigDecimal varr = BigDecimal.ZERO; + if(!this.weightsSupplied){ + System.out.println("weightedVariance_as_BigDecimal: no weights supplied - unweighted value returned"); + varr = this.variance_as_BigDecimal(); + } + else{ + BigDecimal weightedVariance = BigDecimal.ZERO; + switch(this.type){ + case 1: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wd = amWeights.getArray_as_BigDecimal(); + weightedVariance = Stat.variance(bd, wd); + bd = null; + wd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to BigDecimal"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + varr = weightedVariance; + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + return varr; + } + + + public Complex weightedVariance_as_Complex(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + Complex varr = Complex.zero(); + if(!this.weightsSupplied){ + System.out.println("weightedVariance_as_Complex: no weights supplied - unweighted value returned"); + varr = this.variance_as_Complex(); + } + else{ + Complex weightedVariance = Complex.zero(); + Complex[] cc = this.getArray_as_Complex(); + Complex[] wc = amWeights.getArray_as_Complex(); + weightedVariance = Stat.variance(cc, wc); + varr = weightedVariance; + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + return varr; + } + + public double weightedVariance_as_Complex_ConjugateCalcn(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double varr = Double.NaN; + if(!this.weightsSupplied){ + System.out.println("weightedVariance_as_Complex: no weights supplied - unweighted value returned"); + varr = this.variance_as_Complex_ConjugateCalcn(); + } + else{ + Complex[] cc = this.getArray_as_Complex(); + Complex[] wc = amWeights.getArray_as_Complex(); + varr = Stat.varianceConjugateCalcn(cc, wc); + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + return varr; + } + + public double weightedVariance_of_ComplexModuli(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double varr = Double.NaN; + if(!this.weightsSupplied){ + System.out.println("weightedVariance_as_Complex: no weights supplied - unweighted value returned"); + varr = this.variance_of_ComplexModuli(); + } + else{ + double[] cc = this.array_as_modulus_of_Complex(); + double[] wc = amWeights.array_as_modulus_of_Complex(); + varr = Stat.variance(cc, wc); + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + return varr; + } + + public double weightedVariance_of_ComplexRealParts(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double varr = Double.NaN; + if(!this.weightsSupplied){ + System.out.println("weightedVariance_as_Complex: no weights supplied - unweighted value returned"); + varr = this.variance_of_ComplexRealParts(); + } + else{ + double[] cc = this.array_as_real_part_of_Complex(); + double[] wc = amWeights.array_as_real_part_of_Complex(); + varr = Stat.variance(cc, wc); + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + return varr; + } + + public double weightedVariance_of_ComplexImaginaryParts(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double varr = Double.NaN; + if(!this.weightsSupplied){ + System.out.println("weightedVariance_as_Complex: no weights supplied - unweighted value returned"); + varr = this.variance_of_ComplexImaginaryParts(); + } + else{ + double[] cc = this.array_as_imaginary_part_of_Complex(); + double[] wc = amWeights.array_as_imaginary_part_of_Complex(); + varr = Stat.variance(cc, wc); + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + return varr; + } + + + + // STANDARD DEVIATIONS (INSTANCE METHODS) + public double standardDeviation(){ + return this.standardDeviation_as_double(); + } + + public double standardDeviation_as_double(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + + double variance = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + variance = Stat.variance(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + variance = (Stat.variance(bd)).doubleValue(); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.nFactorOptionS = hold; + return Math.sqrt(variance); + } + + public Complex standardDeviation_as_Complex(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + + Complex variance = Complex.zero(); + Complex[] cc = this.getArray_as_Complex(); + variance = Stat.variance(cc); + Stat.nFactorOptionS = hold; + return Complex.sqrt(variance); + } + + public double standardDeviation_as_Complex_ConjugateCalcn(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + + Complex[] cc = this.getArray_as_Complex(); + double variance = Stat.varianceConjugateCalcn(cc); + Stat.nFactorOptionS = hold; + return Math.sqrt(variance); + } + + public double standardDeviation_of_ComplexModuli(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double[] re = this.array_as_modulus_of_Complex(); + double standardDeviation = Stat.standardDeviation(re); + Stat.nFactorOptionS = hold; + return standardDeviation; + } + + public double standardDeviation_of_ComplexRealParts(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double[] re = this.array_as_real_part_of_Complex(); + double standardDeviation = Stat.standardDeviation(re); + Stat.nFactorOptionS = hold; + return standardDeviation; + } + + public double standardDeviation_of_ComplexImaginaryParts(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double[] im = this.array_as_imaginary_part_of_Complex(); + double standardDeviation = Stat.standardDeviation(im); + Stat.nFactorOptionS = hold; + return standardDeviation; + } + + // WEIGHTED STANDARD DEVIATION (INSTANCE METHODS) + public double weightedStandardDeviation(){ + return this.weightedStandardDeviation_as_double(); + } + + public double weightedStandardDeviation_as_double(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + + double varr = 0.0; + if(!this.weightsSupplied){ + System.out.println("weightedStandardDeviation_as_double: no weights supplied - unweighted value returned"); + varr = this.standardDeviation_as_double(); + } + else{ + double variance = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + double[] ww = amWeights.getArray_as_double(); + variance = Stat.variance(dd, ww); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wd = amWeights.getArray_as_BigDecimal(); + variance = (Stat.variance(bd, wd)).doubleValue(); + bd = null; + wd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + varr = Math.sqrt(variance); + + } + Stat.nFactorOptionS = hold; + Stat.weightingOptionS = holdW; + return varr; + } + + + public Complex weightedStandardDeviation_as_Complex(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + + Complex varr = Complex.zero(); + if(!this.weightsSupplied){ + System.out.println("weightedtandardDeviationS_as_Complex: no weights supplied - unweighted value returned"); + varr = this.standardDeviation_as_Complex(); + } + else{ + Complex variance = Complex.zero(); + Complex[] cc = this.getArray_as_Complex(); + Complex[] wc = amWeights.getArray_as_Complex(); + variance = Stat.variance(cc, wc); + varr = Complex.sqrt(variance); + } + Stat.nFactorOptionS = hold; + Stat.weightingOptionS = holdW; + return varr; + + } + + public double weightedStandardDeviation_as_Complex_ConjugateCalcn(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double varr = Double.NaN; + if(!this.weightsSupplied){ + System.out.println("weightedtandardDeviationS_as_Complex: no weights supplied - unweighted value returned"); + varr = this.standardDeviation_as_Complex_ConjugateCalcn(); + } + else{ + double variance = Double.NaN; + Complex[] cc = this.getArray_as_Complex(); + Complex[] wc = amWeights.getArray_as_Complex(); + variance = Stat.varianceConjugateCalcn(cc, wc); + varr = Math.sqrt(variance); + } + Stat.nFactorOptionS = hold; + Stat.weightingOptionS = holdW; + return varr; + + } + + public double weightedStandardDeviation_of_ComplexModuli(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double varr = Double.NaN; + if(!this.weightsSupplied){ + System.out.println("weightedStandardDeviation_as_Complex: no weights supplied - unweighted value returned"); + varr = this.standardDeviation_of_ComplexModuli(); + } + else{ + double[] cc = this.array_as_modulus_of_Complex(); + double[] wc = amWeights.array_as_modulus_of_Complex(); + varr = Stat.standardDeviation(cc, wc); + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + return varr; + } + + public double weightedStandardDeviation_of_ComplexRealParts(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double varr = Double.NaN; + if(!this.weightsSupplied){ + System.out.println("weightedStandardDeviation_as_Complex: no weights supplied - unweighted value returned"); + varr = this.standardDeviation_of_ComplexRealParts(); + } + else{ + double[] cc = this.array_as_real_part_of_Complex(); + double[] wc = amWeights.array_as_real_part_of_Complex(); + varr = Stat.standardDeviation(cc, wc); + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + return varr; + } + + + public double weightedStandardDeviation_of_ComplexImaginaryParts(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double varr = Double.NaN; + if(!this.weightsSupplied){ + System.out.println("weightedStandardDeviation_as_Complex: no weights supplied - unweighted value returned"); + varr = this.standardDeviation_of_ComplexImaginaryParts(); + } + else{ + double[] cc = this.array_as_imaginary_part_of_Complex(); + double[] wc = amWeights.array_as_imaginary_part_of_Complex(); + varr = Stat.standardDeviation(cc, wc); + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + return varr; + } + + + + + + // STANDARD ERROR OF THE MEAN (INSTANCE METHODS) + public double standardError(){ + return this.standardError_as_double(); + } + + public double standardError_as_double(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + + double standardError = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + standardError = Stat.standardError(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + standardError = Stat.standardError(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.nFactorOptionS = hold; + return standardError; + } + + public Complex standardError_as_Complex(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + + Complex standardError = Complex.zero(); + Complex[] cc = this.getArray_as_Complex(); + standardError = Stat.standardError(cc); + Stat.nFactorOptionS = hold; + return standardError; + } + + public double standardError_as_Complex_ConjugateCalcn(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + Complex[] cc = this.getArray_as_Complex(); + double standardError = Stat.standardErrorConjugateCalcn(cc); + Stat.nFactorOptionS = hold; + return standardError; + } + + public double standardError_of_ComplexModuli(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double[] re = this.array_as_modulus_of_Complex(); + double standardError = Stat.standardError(re); + Stat.nFactorOptionS = hold; + return standardError; + } + + public double standardError_of_ComplexRealParts(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double[] re = this.array_as_real_part_of_Complex(); + double standardError = Stat.standardError(re); + Stat.nFactorOptionS = hold; + return standardError; + } + + public double standardError_of_ComplexImaginaryParts(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double[] re = this.array_as_imaginary_part_of_Complex(); + double standardError = Stat.standardError(re); + Stat.nFactorOptionS = hold; + return standardError; + } + + // WEIGHTED STANDARD ERROR OF THE MEAN (INSTANCE METHODS) + public double weightedStandardError(){ + return this.weightedStandardError_as_double(); + } + + public double weightedStandardError_as_double(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + + double standardError = 0.0; + if(!this.weightsSupplied){ + System.out.println("weightedStandardError_as_double: no weights supplied - unweighted value returned"); + standardError = this.standardError_as_double(); + } + else{ + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + double[] ww = amWeights.getArray_as_double(); + standardError = Stat.standardError(dd, ww); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] wd = amWeights.getArray_as_BigDecimal(); + standardError = Stat.standardError(bd, wd); + bd = null; + wd = null; + break; + case 14: throw new IllegalArgumentException("Complex cannot be converted to double"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + standardError = Math.sqrt(standardError); + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + return standardError; + } + + + public Complex weightedStandarError_as_Complex(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + + Complex standardError = Complex.zero(); + if(!this.weightsSupplied){ + System.out.println("weightedStandardError_as_Complex: no weights supplied - unweighted value returned"); + standardError = this.standardError_as_Complex(); + } + else{ + Complex[] cc = this.getArray_as_Complex(); + Complex[] wc = amWeights.getArray_as_Complex(); + standardError = Stat.standardError(cc, wc); + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + + return standardError; + + } + + + public double weightedStandarError_as_Complex_ConjugateCalcn(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double standardError = Double.NaN; + if(!this.weightsSupplied){ + System.out.println("weightedStandardError_as_Complex: no weights supplied - unweighted value returned"); + standardError = this.standardError_as_Complex_ConjugateCalcn(); + } + else{ + Complex[] cc = this.getArray_as_Complex(); + Complex[] wc = amWeights.getArray_as_Complex(); + standardError = Stat.standardErrorConjugateCalcn(cc, wc); + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + + return standardError; + + } + + public double weightedStandardError_of_ComplexModuli(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double varr = Double.NaN; + if(!this.weightsSupplied){ + System.out.println("weightedStandardError_as_Complex: no weights supplied - unweighted value returned"); + varr = this.standardError_of_ComplexModuli(); + } + else{ + double[] cc = this.array_as_modulus_of_Complex(); + double[] wc = amWeights.array_as_modulus_of_Complex(); + varr = Stat.standardError(cc, wc); + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + return varr; + } + + public double weightedStandardError_of_ComplexRealParts(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double varr = Double.NaN; + if(!this.weightsSupplied){ + System.out.println("weightedStandardError_as_Complex: no weights supplied - unweighted value returned"); + varr = this.standardError_of_ComplexRealParts(); + } + else{ + double[] cc = this.array_as_real_part_of_Complex(); + double[] wc = amWeights.array_as_real_part_of_Complex(); + varr = Stat.standardError(cc, wc); + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + return varr; + } + + + public double weightedStandardError_of_ComplexImaginaryParts(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean hold2 = Stat.nEffOptionS; + if(this.nEffReset){ + if(this.nEffOptionI){ + Stat.nEffOptionS = true; + } + else{ + Stat.nEffOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double varr = Double.NaN; + if(!this.weightsSupplied){ + System.out.println("weightedStandardError_as_Complex: no weights supplied - unweighted value returned"); + varr = this.standardError_of_ComplexImaginaryParts(); + } + else{ + double[] cc = this.array_as_imaginary_part_of_Complex(); + double[] wc = amWeights.array_as_imaginary_part_of_Complex(); + varr = Stat.standardError(cc, wc); + } + Stat.nFactorOptionS = hold; + Stat.nEffOptionS = hold2; + Stat.weightingOptionS = holdW; + return varr; + } + + + + + // STANDARDIZE (INSTANCE METHODS) + // Standardization of the internal array to a mean of 0 and a standard deviation of 1 + public double[] standardize(){ + double[] bb = null; + switch(this.type){ + case 1: + case 12: double[] dd = this.getArray_as_double(); + bb = Stat.standardize(dd); + break; + case 14: throw new IllegalArgumentException("Standardization of Complex is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return bb; + } + + public double[] standardise(){ + return standardize(); + } + + + // SCALE (INSTANCE METHODS) + // Scale the internal array to a new mean and a new standard deviation + public double[] scale(double mean, double sd){ + double[] bb = null; + switch(this.type){ + case 1: + case 12: double[] dd = this.getArray_as_double(); + bb = Stat.scale(dd, mean, sd); + break; + case 14: throw new IllegalArgumentException("Scaling of Complex is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return bb; + } + + + + // VOLATILITY (INSTANCE METHODS) + public double volatilityLogChange(){ + double volatilityLogChange = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + volatilityLogChange = Stat.volatilityLogChange(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + volatilityLogChange = Stat.volatilityLogChange(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex volatilty is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return volatilityLogChange; + } + + public double volatilityPerCentChange(){ + double volatilityPerCentChange = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + volatilityPerCentChange = Stat.volatilityPerCentChange(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + volatilityPerCentChange = Stat.volatilityPerCentChange(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex volatilty is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return volatilityPerCentChange; + } + + //COEFFICIENT OF VARIATION + public double coefficientOfVariation(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + double coefficientOfVariation = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + coefficientOfVariation = Stat.coefficientOfVariation(dd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + coefficientOfVariation = Stat.coefficientOfVariation(bd); + bd = null; + break; + case 14: throw new IllegalArgumentException("Complex coefficient of variation is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.nFactorOptionS = hold; + return coefficientOfVariation; + } + + public double weightedCoefficientOfVariation(){ + boolean hold = Stat.nFactorOptionS; + if(this.nFactorReset){ + if(this.nFactorOptionI){ + Stat.nFactorOptionS = true; + } + else{ + Stat.nFactorOptionS = false; + } + } + boolean holdW = Stat.weightingOptionS; + if(this.weightingReset){ + if(this.weightingOptionI){ + Stat.weightingOptionS = true; + } + else{ + Stat.weightingOptionS = false; + } + } + double coefficientOfVariation = 0.0D; + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + double[] wd = amWeights.getArray_as_double(); + coefficientOfVariation = Stat.coefficientOfVariation(dd, wd); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal[] bw = amWeights.getArray_as_BigDecimal(); + coefficientOfVariation = Stat.coefficientOfVariation(bd, bw); + bd = null; + bw = null; + break; + case 14: throw new IllegalArgumentException("Complex coefficient of variation is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + Stat.nFactorOptionS = hold; + Stat.weightingOptionS = holdW; + return coefficientOfVariation; + } + + // SHANNON ENTROPY (INSTANCE METHODS) + // return Shannon entropy as bits + public double shannonEntropy(){ + double entropy = 0.0D; + switch(this.type){ + case 1: + case 12: double[] dd = this.getArray_as_double(); + entropy = Stat.shannonEntropy(dd); + break; + case 14: throw new IllegalArgumentException("Complex Shannon Entropy is not meaningful"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return entropy; + } + + // return Shannon entropy as bits + public double shannonEntropyBit(){ + double entropy = 0.0D; + switch(this.type){ + case 1: + case 12: double[] dd = this.getArray_as_double(); + entropy = Stat.shannonEntropy(dd); + break; + case 14: throw new IllegalArgumentException("Complex Shannon Entropy is not meaningful"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return entropy; + } + + // return Shannon entropy as nats + public double shannonEntropyNat(){ + double entropy = 0.0D; + switch(this.type){ + case 1: + case 12: double[] dd = this.getArray_as_double(); + entropy = Stat.shannonEntropyNat(dd); + break; + case 14: throw new IllegalArgumentException("Complex Shannon Entropy is not meaningful"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return entropy; + } + + // return Shannon entropy as dits + public double shannonEntropyDit(){ + double entropy = 0.0D; + switch(this.type){ + case 1: + case 12: double[] dd = this.getArray_as_double(); + entropy = Stat.shannonEntropyDit(dd); + break; + case 14: throw new IllegalArgumentException("Complex Shannon Entropy is not meaningful"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return entropy; + } + + // RENYI ENTROPY (INSTANCE METHODS) + // return Renyi entropy as bits + public double renyiEntropy(double alpha){ + double entropy = 0.0D; + switch(this.type){ + case 1: + case 12: double[] dd = this.getArray_as_double(); + entropy = Stat.renyiEntropy(dd, alpha); + break; + case 14: throw new IllegalArgumentException("Complex Renyi Entropy is not meaningful"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return entropy; + } + + // return Renyi entropy as bits + public double renyiEntropyBit(double alpha){ + double entropy = 0.0D; + switch(this.type){ + case 1: + case 12: double[] dd = this.getArray_as_double(); + entropy = Stat.renyiEntropy(dd, alpha); + break; + case 14: throw new IllegalArgumentException("Complex Renyi Entropy is not meaningful"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return entropy; + } + + // return Renyi entropy as nats + public double renyiEntropyNat(double alpha){ + double entropy = 0.0D; + switch(this.type){ + case 1: + case 12: double[] dd = this.getArray_as_double(); + entropy = Stat.renyiEntropyNat(dd, alpha); + break; + case 14: throw new IllegalArgumentException("Complex Renyi Entropy is not meaningful"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return entropy; + } + + // return Renyi entropy as dits + public double renyiEntropyDit(double alpha){ + double entropy = 0.0D; + switch(this.type){ + case 1: + case 12: double[] dd = this.getArray_as_double(); + entropy = Stat.renyiEntropyDit(dd, alpha); + break; + case 14: throw new IllegalArgumentException("Complex Renyi Entropy is not meaningful"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return entropy; + } + + // TSALLIS ENTROPY (INSTANCE METHODS) + // return Tsallis entropy + public double tsallisEntropyNat(double q){ + double entropy = 0.0D; + switch(this.type){ + case 1: + case 12: double[] dd = this.getArray_as_double(); + entropy = Stat.tsallisEntropyNat(dd, q); + break; + case 14: throw new IllegalArgumentException("Complex Tsallis Entropy is not meaningful"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return entropy; + } + + + // GENERALIZED ENTROPY (INSTANCE METHODS) + // return generalised entropy + public double generalizedEntropyOneNat(double q, double r){ + double entropy = 0.0D; + switch(this.type){ + case 1: + case 12: double[] dd = this.getArray_as_double(); + entropy = Stat.generalizedEntropyOneNat(dd, q, r); + break; + case 14: throw new IllegalArgumentException("Complex Generalized Entropy is not meaningful"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + return entropy; + } + + public double generalisedEntropyOneNat(double q, double r){ + return generalizedEntropyOneNat(q, r); + } + + // OUTLIER DETECTION (INSTANCE) + // Anscombe test for a upper outlier + public ArrayList<Object> upperOutliersAnscombe(double constant){ + return this.upperOutliersAnscombe_as_double(constant); + } + + // Anscombe test for a upper outlier + public ArrayList<Object> upperOutliersAnscombe_as_double(double constant){ + + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + this.upperOutlierDetails = upperOutliersAnscombeAsArrayList(dd, constant); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + ArrayList<Object> ret = new ArrayList<Object>(); + ret = upperOutliersAnscombeAsArrayList(bd, new BigDecimal(constant)); + this.upperOutlierDetails.add((Integer)ret.get(0)); + BigDecimal[] bd1 = (BigDecimal[])ret.get(1); + ArrayMaths am1 = new ArrayMaths(bd1); + this.upperOutlierDetails.add(am1.getArray_as_Double()); + this.upperOutlierDetails.add((int[])ret.get(2)); + BigDecimal[] bd2 = (BigDecimal[])ret.get(3); + ArrayMaths am2 = new ArrayMaths(bd2); + this.upperOutlierDetails.add(am2.getArray_as_Double()); + break; + case 14: throw new IllegalArgumentException("Outlier detection of Complex is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + this.upperDone = true; + return this.upperOutlierDetails; + } + + // Anscombe test for a upper outlier + public ArrayList<Object> upperOutliersAnscombe(BigDecimal constant){ + return this.upperOutliersAnscombe_as_BigDecimal(constant); + } + + // Anscombe test for a upper outlier + public ArrayList<Object> upperOutliersAnscombe_as_BigDecimal(BigDecimal constant){ + + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + ArrayList<Object> ret = new ArrayList<Object>(); + ret = upperOutliersAnscombeAsArrayList(dd, constant.doubleValue()); + this.upperOutlierDetails.add((Integer)ret.get(0)); + Double[] dd1 = (Double[])ret.get(1); + ArrayMaths am1 = new ArrayMaths(dd1); + this.upperOutlierDetails.add(am1.getArray_as_BigDecimal()); + this.upperOutlierDetails.add((int[])ret.get(2)); + Double[] dd2 = (Double[])ret.get(3); + ArrayMaths am2 = new ArrayMaths(dd2); + this.upperOutlierDetails.add(am2.getArray_as_BigDecimal()); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + this.upperOutlierDetails = upperOutliersAnscombeAsArrayList(bd, constant); + break; + case 14: throw new IllegalArgumentException("Outlier detection of Complex is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + this.upperDone = true; + return this.upperOutlierDetails; + } + + + public ArrayList<Object> upperOutliersAnscombe(BigInteger constant){ + return this.upperOutliersAnscombe_as_BigDecimal(new BigDecimal(constant)); + } + + public ArrayList<Object> upperOutliersAnscombe_as_BigDecimal(BigInteger constant){ + return this.upperOutliersAnscombe_as_BigDecimal(new BigDecimal(constant)); + } + + // Anscombe test for a lower outlier + public ArrayList<Object> lowerOutliersAnscombe(double constant){ + return this.lowerOutliersAnscombe_as_double(constant); + } + + // Anscombe test for a lower outlier + public ArrayList<Object> lowerOutliersAnscombe_as_double(double constant){ + + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + this.lowerOutlierDetails = lowerOutliersAnscombeAsArrayList(dd, constant); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + ArrayList<Object> ret = new ArrayList<Object>(); + ret = lowerOutliersAnscombeAsArrayList(bd, new BigDecimal(constant)); + this.lowerOutlierDetails.add((Integer)ret.get(0)); + BigDecimal[] bd1 = (BigDecimal[])ret.get(1); + ArrayMaths am1 = new ArrayMaths(bd1); + this.lowerOutlierDetails.add(am1.getArray_as_Double()); + this.lowerOutlierDetails.add((int[])ret.get(2)); + BigDecimal[] bd2 = (BigDecimal[])ret.get(3); + ArrayMaths am2 = new ArrayMaths(bd2); + this.lowerOutlierDetails.add(am2.getArray_as_Double()); + break; + case 14: throw new IllegalArgumentException("Outlier detection of Complex is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + this.lowerDone = true; + return this.lowerOutlierDetails; + } + + public ArrayList<Object> lowerOutliersAnscombe(BigDecimal constant){ + return this.lowerOutliersAnscombe_as_BigDecimal(constant); + } + + + public ArrayList<Object> lowerOutliersAnscombe_as_BigDecimal(BigDecimal constant){ + + switch(this.type){ + case 1: double[] dd = this.getArray_as_double(); + ArrayList<Object> ret = new ArrayList<Object>(); + ret = lowerOutliersAnscombeAsArrayList(dd, constant.doubleValue()); + this.lowerOutlierDetails.add((Integer)ret.get(0)); + Double[] dd1 = (Double[])ret.get(1); + ArrayMaths am1 = new ArrayMaths(dd1); + this.lowerOutlierDetails.add(am1.getArray_as_BigDecimal()); + this.lowerOutlierDetails.add((int[])ret.get(2)); + Double[] dd2 = (Double[])ret.get(3); + ArrayMaths am2 = new ArrayMaths(dd2); + this.lowerOutlierDetails.add(am2.getArray_as_BigDecimal()); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + this.lowerOutlierDetails = lowerOutliersAnscombeAsArrayList(bd, constant); + break; + case 14: throw new IllegalArgumentException("Outlier detection of Complex is not supported"); + default: throw new IllegalArgumentException("This type number, " + this.type +", should not be possible here!!!!"); + } + this.lowerDone = true; + return this.lowerOutlierDetails; + } + + public ArrayList<Object> lowerOutliersAnscombe(BigInteger constant){ + return this.lowerOutliersAnscombe_as_BigDecimal(new BigDecimal(constant)); + } + + public ArrayList<Object> lowerOutliersAnscombe_as_BigDecimal(BigInteger constant){ + return this.lowerOutliersAnscombe_as_BigDecimal(new BigDecimal(constant)); + } + + + // STATIC METHODS + // WEIGHTING CHOICE (STATIC) + // Set weights to 'big W' - multiplicative factor + public static void setStaticWeightsToBigW(){ + Stat.weightingOptionS = false; + } + + // Set weights to 'little w' - uncertainties + public static void setStaticWeightsToLittleW(){ + Stat.weightingOptionS = true; + } + + // CONVERSION OF WEIGHTING FACTORS + // Converts weighting facors Wi to wi, i.e. to 1/sqrt(Wi) + public static double[] convertBigWtoLittleW(double[] bigW){ + ArrayMaths am1 = new ArrayMaths(bigW); + ArrayMaths am2 = am1.oneOverSqrt(); + return am2.getArray_as_double(); + } + + public static float[] convertBigWtoLittleW(float[] bigW){ + ArrayMaths am1 = new ArrayMaths(bigW); + ArrayMaths am2 = am1.oneOverSqrt(); + return am2.getArray_as_float(); + } + + public static Complex[] convertBigWtoLittleW(Complex[] bigW){ + ArrayMaths am1 = new ArrayMaths(bigW); + ArrayMaths am2 = am1.oneOverSqrt(); + return am2.getArray_as_Complex(); + } + + public static double[] convertBigWtoLittleW(BigDecimal[] bigW){ + ArrayMaths am1 = new ArrayMaths(bigW); + ArrayMaths am2 = am1.oneOverSqrt(); + return am2.getArray_as_double(); + } + + public static double[] convertBigWtoLittleW(BigInteger[] bigW){ + ArrayMaths am1 = new ArrayMaths(bigW); + ArrayMaths am2 = am1.oneOverSqrt(); + return am2.getArray_as_double(); + } + + // private weighting calculation + // returns weight w + // litte w to one over little w squared if uncertainties used + private static double[] invertAndSquare(double[] ww){ + double[] weight = ww.clone(); + if(Stat.weightingOptionS){ + ArrayMaths am = new ArrayMaths(ww); + am = am.pow(2); + am = am.invert(); + weight = am.array(); + } + return weight; + } + + private static float[] invertAndSquare(float[] ww){ + float[] weight = ww.clone(); + if(Stat.weightingOptionS){ + ArrayMaths am = new ArrayMaths(ww); + am = am.pow(2); + am = am.invert(); + weight = am.array_as_float(); + } + return weight; + } + + private static Complex[] invertAndSquare(Complex[] ww){ + Complex[] weight = ww.clone(); + if(Stat.weightingOptionS){ + ArrayMaths am = new ArrayMaths(ww); + am = am.pow(2); + am = am.invert(); + weight = am.array_as_Complex(); + } + return weight; + } + + private static BigDecimal[] invertAndSquare(BigDecimal[] ww){ + BigDecimal[] weight = ww.clone(); + if(Stat.weightingOptionS){ + ArrayMaths am = new ArrayMaths(ww); + am = am.pow(2); + am = am.invert(); + weight = am.array_as_BigDecimal(); + } + return weight; + } + + private static BigDecimal[] invertAndSquare(BigInteger[] ww){ + ArrayMaths am = new ArrayMaths(ww); + BigDecimal[] weight = am.array_as_BigDecimal(); + if(Stat.weightingOptionS){ + am = am.pow(2); + am = am.invert(); + weight = am.array_as_BigDecimal(); + } + return weight; + } + + + + // DENOMINATOR CHOICE (STATIC) + // Set standard deviation, variance and covariance denominators to n + public static void setStaticDenominatorToN(){ + Stat.nFactorOptionS = true; + } + + // Set standard deviation, variance and covariance denominators to n + public static void setStaticDenominatorToNminusOne(){ + Stat.nFactorOptionS = false; + } + + + // EFFECTIVE SAMPLE NUMBER + // Repalce number of data points to the effective sample number in weighted calculations + public static void useStaticEffectiveN(){ + Stat.nEffOptionS = true; + } + + // Repalce the effective sample number in weighted calculations by the number of data points + public static void useStaticTrueN(){ + Stat.nEffOptionS = false; + } + + // Calculation of the effective sample number (double) + public static double effectiveSampleNumber(double[] ww){ + double[] weight = ww.clone(); + if(Stat.weightingOptionS){ + ArrayMaths am = new ArrayMaths(ww); + am = am.pow(2); + am = am.invert(); + weight = am.array(); + } + int n = weight.length; + + double nEff = n; + if(Stat.nEffOptionS){ + double sum2w = 0.0D; + double sumw2 = 0.0D; + for(int i=0; i<n; i++){ + sum2w += weight[i]; + sumw2 += weight[i]*weight[i]; + } + sum2w *= sum2w; + nEff = sum2w/sumw2; + } + return nEff; + } + + // Calculation of the sample number (float) + public static float effectiveSampleNumber(float[] ww){ + float[] weight = ww.clone(); + if(Stat.weightingOptionS){ + ArrayMaths am = new ArrayMaths(ww); + am = am.pow(2); + am = am.invert(); + weight = am.array_as_float(); + } + int n = weight.length; + + float nEff = n; + if(Stat.nEffOptionS){ + float sum2w = 0.0F; + float sumw2 = 0.0F; + for(int i=0; i<n; i++){ + sum2w += weight[i]; + sumw2 += weight[i]*weight[i]; + } + sum2w *= sum2w; + nEff = sum2w/sumw2; + } + return nEff; + } + + // Calculation of the sample number (Complex) + public static Complex effectiveSampleNumber(Complex[] ww){ + Complex[] weight = ww.clone(); + if(Stat.weightingOptionS){ + ArrayMaths am = new ArrayMaths(ww); + am = am.pow(2); + am = am.invert(); + weight = am.array_as_Complex(); + } + int n = weight.length; + + Complex nEff = new Complex(n, 0.0); + if(Stat.nEffOptionS){ + Complex sumw2 = Complex.zero(); + Complex sum2w = Complex.zero(); + for(int i=0; i<n; i++){ + sum2w = sum2w.plus(weight[i]); + sumw2 = sumw2.plus(weight[i].times(weight[i])); + } + sum2w = sum2w.times(sum2w); + nEff = sum2w.over(sumw2); + } + return nEff; + } + + // Calculation of the sample number (Complex - Conjugate formula) + public static double effectiveSampleNumberConjugateCalcn(Complex[] ww){ + Complex[] weight = ww.clone(); + if(Stat.weightingOptionS){ + ArrayMaths am = new ArrayMaths(ww); + am = am.pow(2); + am = am.invert(); + weight = am.array_as_Complex(); + } + int n = weight.length; + + double nEff = Double.NaN; + if(Stat.nEffOptionS){ + Complex sumw2 = Complex.zero(); + Complex sum2w = Complex.zero(); + for(int i=0; i<n; i++){ + sum2w = sum2w.plus(weight[i]); + sumw2 = sumw2.plus(weight[i].times(weight[i].conjugate())); + } + sum2w = sum2w.times(sum2w.conjugate()); + nEff = sum2w.getReal()/sumw2.getReal(); + } + return nEff; + } + + // Calculation of the sample number (BigDecimal) + public static BigDecimal effectiveSampleNumber(BigDecimal[] ww){ + BigDecimal[] weight = ww.clone(); + if(Stat.weightingOptionS){ + ArrayMaths am = new ArrayMaths(ww); + am = am.pow(2); + am = am.invert(); + weight = am.array_as_BigDecimal(); + } + int n = weight.length; + + BigDecimal nEff = new BigDecimal(new Integer(n).toString()); + if(Stat.nEffOptionS){ + BigDecimal sumw2 = BigDecimal.ZERO; + BigDecimal sum2w = BigDecimal.ZERO; + for(int i=0; i<n; i++){ + sum2w = sum2w.add(weight[i]); + sumw2 = sumw2.add(weight[i].multiply(weight[i])); + } + sum2w = sum2w.multiply(sum2w); + nEff = sum2w.divide(sumw2, BigDecimal.ROUND_HALF_UP); + sumw2 = null; + sum2w = null; + weight = null; + } + return nEff; + } + + public static BigDecimal effectiveSampleNumber(BigInteger[] ww){ + ArrayMaths am = new ArrayMaths(ww); + BigDecimal[] www = am.array_as_BigDecimal(); + return Stat.effectiveSampleNumber(www); + } + + + // ARITMETIC MEANS (STATIC) + + // Arithmetic mean of a 1D array of doubles, aa + public static double mean(double[] aa){ + int n = aa.length; + double sum=0.0D; + for(int i=0; i<n; i++){ + sum+=aa[i]; + } + return sum/((double)n); + } + + // Arithmetic mean of a 1D array of floats, aa + public static float mean(float[] aa){ + int n = aa.length; + float sum=0.0F; + for(int i=0; i<n; i++){ + sum+=aa[i]; + } + return sum/((float)n); + } + + // Arithmetic mean of a 1D array of int, aa + public static double mean(long[] aa){ + int n = aa.length; + double sum=0.0D; + for(int i=0; i<n; i++){ + sum+=(double)aa[i]; + } + return sum/((double)n); + } + + // Arithmetic mean of a 1D array of int, aa + public static double mean(int[] aa){ + int n = aa.length; + double sum=0.0D; + for(int i=0; i<n; i++){ + sum+=(double)aa[i]; + } + return sum/((double)n); + } + + // Arithmetic mean of a 1D array of short, aa + public static double mean(short[] aa){ + int n = aa.length; + double sum=0.0D; + for(int i=0; i<n; i++){ + sum+=(double)aa[i]; + } + return sum/((double)n); + } + + // Arithmetic mean of a 1D array of byte, aa + public static double mean(byte[] aa){ + int n = aa.length; + double sum=0.0D; + for(int i=0; i<n; i++){ + sum+=(double)aa[i]; + } + return sum/((double)n); + } + + // Arithmetic mean of a 1D array of Complex, aa + public static Complex mean(Complex[] aa){ + int n = aa.length; + Complex sum = new Complex(0.0D, 0.0D); + for(int i=0; i<n; i++){ + sum = sum.plus(aa[i]); + } + return sum.over((double)n); + } + + // Arithmetic mean of a 1D array of BigDecimal, aa + public static BigDecimal mean(BigDecimal[] aa){ + int n = aa.length; + BigDecimal sum = BigDecimal.ZERO; + for(int i=0; i<n; i++){ + sum = sum.add(aa[i]); + } + return sum.divide(new BigDecimal((double)n), BigDecimal.ROUND_HALF_UP); + } + + // Arithmetic mean of a 1D array of BigInteger, aa + public static BigDecimal mean(BigInteger[] aa){ + int n = aa.length; + BigDecimal sum = BigDecimal.ZERO; + BigDecimal bi = BigDecimal.ZERO; + for(int i=0; i<n; i++){ + bi = new BigDecimal(aa[i]); + sum = sum.add(bi); + } + bi = null; + return sum.divide(new BigDecimal((double)n), BigDecimal.ROUND_HALF_UP); + } + + + + + // WEIGHTED ARITHMETIC MEANS (STATIC) + // Weighted arithmetic mean of a 1D array of doubles, aa + public static double mean(double[] aa, double[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + double[] weight = ww.clone(); + if(Stat.weightingOptionS){ + ArrayMaths am = new ArrayMaths(ww); + am = am.pow(2); + am = am.invert(); + weight = am.array(); + } + double sumx=0.0D; + double sumw=0.0D; + for(int i=0; i<n; i++){ + sumx+=aa[i]*weight[i]; + sumw+=weight[i]; + } + return sumx/sumw; + } + + // Weighted arithmetic mean of a 1D array of floats, aa + public static float mean(float[] aa, float[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + float[] weight = ww.clone(); + if(Stat.weightingOptionS){ + ArrayMaths am = new ArrayMaths(ww); + am = am.pow(2); + am = am.invert(); + weight = am.array_as_float(); + } + + float sumx=0.0F; + float sumw=0.0F; + for(int i=0; i<n; i++){ + sumx+=aa[i]*weight[i]; + sumw+=weight[i]; + } + return sumx/sumw; + } + + // Weighted arithmetic mean of a 1D array of Complex, aa + public static Complex mean(Complex[] aa, Complex[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + Complex[] weight = ww.clone(); + if(Stat.weightingOptionS){ + ArrayMaths am = new ArrayMaths(ww); + am = am.pow(2); + am = am.invert(); + weight = am.array_as_Complex(); + } + Complex sumx=Complex.zero(); + Complex sumw=Complex.zero(); + for(int i=0; i<n; i++){ + sumx = sumx.plus(aa[i].times(weight[i])); + sumw = sumw.plus(weight[i]); + } + return sumx.over(sumw); + } + + // Weighted arithmetic mean of a 1D array of BigDecimal, aa + public static BigDecimal mean(BigDecimal[] aa, BigDecimal[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + BigDecimal[] weight = ww.clone(); + if(Stat.weightingOptionS){ + ArrayMaths am = new ArrayMaths(ww); + am = am.pow(2); + am = am.invert(); + weight = am.array_as_BigDecimal(); + } + + BigDecimal sumx =BigDecimal.ZERO; + BigDecimal sumw =BigDecimal.ZERO; + for(int i=0; i<n; i++){ + sumx = sumx.add(aa[i].multiply(weight[i])); + sumw = sumw.add(weight[i]); + } + sumx = sumx.divide(sumw, BigDecimal.ROUND_HALF_UP); + sumw = null; + weight = null; + return sumx; + } + + // Weighted arithmetic mean of a 1D array of BigInteger, aa + public static BigDecimal mean(BigInteger[] aa, BigInteger[] ww){ + ArrayMaths amaa = new ArrayMaths(aa); + ArrayMaths amww = new ArrayMaths(ww); + + return mean(amaa.array_as_BigDecimal(), amww.array_as_BigDecimal()); + } + + // SUBTRACT THE MEAN (STATIC) + // Subtract arithmetic mean of an array from data array elements + public static double[] subtractMean(double[] array){ + int n = array.length; + double mean = Stat.mean(array); + double[] arrayMinusMean = new double[n]; + for(int i=0; i<n; i++)arrayMinusMean[i] = array[i] - mean; + + return arrayMinusMean; + } + + // Subtract arithmetic mean of an array from data array elements + public static float[] subtractMean(float[] array){ + int n = array.length; + float mean = Stat.mean(array); + float[] arrayMinusMean = new float[n]; + for(int i=0; i<n; i++)arrayMinusMean[i] = array[i] - mean; + + return arrayMinusMean; + } + + + // Subtract arithmetic mean of an array from data array elements + public static BigDecimal[] subtractMean(BigDecimal[] array){ + int n = array.length; + BigDecimal mean = Stat.mean(array); + BigDecimal[] arrayMinusMean = new BigDecimal[n]; + for(int i=0; i<n; i++)arrayMinusMean[i] = array[i].subtract(mean); + mean = null; + return arrayMinusMean; + } + + // Subtract arithmetic mean of an array from data array elements + public static BigDecimal[] subtractMean(BigInteger[] array){ + int n = array.length; + BigDecimal mean = Stat.mean(array); + BigDecimal[] arrayMinusMean = new BigDecimal[n]; + for(int i=0; i<n; i++)arrayMinusMean[i] = (new BigDecimal(array[i])).subtract(mean); + mean = null; + return arrayMinusMean; + } + + // Subtract arithmetic mean of an array from data array elements + public static Complex[] subtractMean(Complex[] array){ + int n = array.length; + Complex mean = Stat.mean(array); + Complex[] arrayMinusMean = new Complex[n]; + for(int i=0; i<n; i++)arrayMinusMean[i] = array[i].minus(mean); + + return arrayMinusMean; + } + + // Subtract weighted arirhmetic mean of an array from data array elements + public static double[] subtractMean(double[] array, double[] weights){ + int n = array.length; + double mean = Stat.mean(array, weights); + double[] arrayMinusMean = new double[n]; + for(int i=0; i<n; i++)arrayMinusMean[i] = array[i] - mean; + + return arrayMinusMean; + } + + // Subtract weighted arirhmetic mean of an array from data array elements + public static float[] subtractMean(float[] array, float[] weights){ + int n = array.length; + float mean = Stat.mean(array, weights); + float[] arrayMinusMean = new float[n]; + for(int i=0; i<n; i++)arrayMinusMean[i] = array[i] - mean; + + return arrayMinusMean; + } + + + // Subtract weighted arirhmetic mean of an array from data array elements + public static BigDecimal[] subtractMean(BigDecimal[] array, BigDecimal[] weights){ + int n = array.length; + BigDecimal mean = Stat.mean(array, weights); + BigDecimal[] arrayMinusMean = new BigDecimal[n]; + for(int i=0; i<n; i++)arrayMinusMean[i] = array[i].subtract(mean); + mean = null; + return arrayMinusMean; + } + + // Subtract weighted arirhmetic mean of an array from data array elements + public static BigDecimal[] subtractMean(BigInteger[] array, BigInteger[] weights){ + int n = array.length; + BigDecimal mean = Stat.mean(array, weights); + BigDecimal[] arrayMinusMean = new BigDecimal[n]; + for(int i=0; i<n; i++)arrayMinusMean[i] = (new BigDecimal(array[i])).subtract(mean); + mean = null; + return arrayMinusMean; + } + + // Subtract weighted arirhmetic mean of an array from data array elements + public static Complex[] subtractMean(Complex[] array, Complex[] weights){ + int n = array.length; + Complex mean = Stat.mean(array, weights); + Complex[] arrayMinusMean = new Complex[n]; + for(int i=0; i<n; i++)arrayMinusMean[i] = array[i].minus(mean); + + return arrayMinusMean; + } + + // GEOMETRIC MEANS (STATIC) + + // Geometric mean of a 1D array of BigDecimal, aa + public static double geometricMean(BigDecimal[] aa){ + int n = aa.length; + double sum = 0.0D; + for(int i=0; i<n; i++)sum += Math.log(aa[i].doubleValue()); + return Math.exp(sum/(double)n); + } + + // Geometric mean of a 1D array of BigInteger, aa + public static double geometricMean(BigInteger[] aa){ + int n = aa.length; + double sum = 0.0D; + for(int i=0; i<n; i++)sum += Math.log(aa[i].doubleValue()); + return Math.exp(sum/(double)n); + } + + // Geometric mean of a 1D array of Complex, aa + public static Complex geometricMean(Complex[] aa){ + int n = aa.length; + Complex sum = Complex.zero(); + for(int i=0; i<n; i++)sum = sum.plus(Complex.log(aa[i])); + return Complex.exp(sum.over((double)n)); + } + + // Geometric mean of a 1D array of doubles, aa + public static double geometricMean(double[] aa){ + int n = aa.length; + double sum=0.0D; + for(int i=0; i<n; i++)sum += Math.log(aa[i]); + return Math.exp(sum/(double)n); + } + + // Geometric mean of a 1D array of floats, aa + public static float geometricMean(float[] aa){ + int n = aa.length; + float sum=0.0F; + for(int i=0; i<n; i++)sum += (float)Math.log(aa[i]); + return (float)Math.exp(sum/(float)n); + } + + // Weighted geometric mean of a 1D array of Complexs, aa + public static Complex geometricMean(Complex[] aa, Complex[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + Complex sumW = Complex.zero(); + Complex[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumW = sumW.plus(weight[i]); + } + Complex sum = Complex.zero(); + for(int i=0; i<n; i++){ + sum = sum.plus(Complex.log(aa[i]).times(weight[i])); + } + return Complex.exp(sum.over(sumW)); + } + + // Weighted geometric mean of a 1D array of BigDecimal, aa + public static double geometricMean(BigDecimal[] aa, BigDecimal[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + ArrayMaths weighting = new ArrayMaths(Stat.invertAndSquare(ww)); + double[] weight = weighting.array(); + + double sumW = 0.0D; + for(int i=0; i<n; i++){ + sumW += weight[i]; + } + double sum=0.0D; + for(int i=0; i<n; i++){ + sum += Math.log(aa[i].doubleValue())*weight[i]; + } + return Math.exp(sum/sumW); + } + + // Weighted geometric mean of a 1D array of BigDecimal, aa + public static double geometricMean(BigInteger[] aa, BigInteger[] ww){ + ArrayMaths amaa = new ArrayMaths(aa); + ArrayMaths amww = new ArrayMaths(ww); + return geometricMean(amaa.array_as_BigDecimal(), amww.array_as_BigDecimal()); + } + + // Weighted geometric mean of a 1D array of double, aa + public static double geometricMean(double[] aa, double[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + double sumW = 0.0D; + double[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumW += weight[i]; + } + double sum=0.0D; + for(int i=0; i<n; i++){ + sum += Math.log(aa[i])*weight[i]; + } + return Math.exp(sum/sumW); + } + + // Weighted geometric mean of a 1D array of floats, aa + public static float geometricMean(float[] aa, float[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + float sumW = 0.0F; + float[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumW += weight[i]; + } + float sum=0.0F; + for(int i=0; i<n; i++){ + sum += (float)Math.log(aa[i])*weight[i]; + } + return (float)Math.exp(sum/sumW); + } + + // HARMONIC MEANS (STATIC) + + // Harmonic mean of a 1D array of BigDecimal, aa + public static BigDecimal harmonicMean(BigDecimal[] aa){ + int n = aa.length; + BigDecimal sum = BigDecimal.ZERO; + for(int i=0; i<n; i++)sum = sum.add(BigDecimal.ONE.divide(aa[i], BigDecimal.ROUND_HALF_UP)); + sum = (new BigDecimal((double)n)).divide(sum, BigDecimal.ROUND_HALF_UP); + return sum; + } + + // Harmonic mean of a 1D array of BigInteger, aa + public static BigDecimal harmonicMean(BigInteger[] aa){ + int n = aa.length; + ArrayMaths am = new ArrayMaths(aa); + BigDecimal[] bd = am.getArray_as_BigDecimal(); + BigDecimal sum = BigDecimal.ZERO; + for(int i=0; i<n; i++)sum = sum.add(BigDecimal.ONE.divide(bd[i], BigDecimal.ROUND_HALF_UP)); + sum = (new BigDecimal((double)n)).divide(sum, BigDecimal.ROUND_HALF_UP); + bd = null; + return sum; + } + + // Harmonic mean of a 1D array of Complex, aa + public static Complex harmonicMean(Complex[] aa){ + int n = aa.length; + Complex sum = Complex.zero(); + for(int i=0; i<n; i++)sum = sum.plus(Complex.plusOne().over(aa[i])); + sum = (new Complex((double)n)).over(sum); + return sum; + } + + // Harmonic mean of a 1D array of doubles, aa + public static double harmonicMean(double[] aa){ + int n = aa.length; + double sum = 0.0D; + for(int i=0; i<n; i++)sum += 1.0D/aa[i]; + return (double)n/sum; + } + + // Harmonic mean of a 1D array of floats, aa + public static float harmonicMean(float[] aa){ + int n = aa.length; + float sum = 0.0F; + for(int i=0; i<n; i++)sum += 1.0F/aa[i]; + return (float)n/sum; + } + + // Weighted harmonic mean of a 1D array of BigDecimal, aa + public static BigDecimal harmonicMean(BigDecimal[] aa, BigDecimal[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + BigDecimal sum = BigDecimal.ZERO; + BigDecimal sumW = BigDecimal.ZERO; + BigDecimal[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumW = sumW.add(weight[i]); + } + for(int i=0; i<n; i++)sum = sum.add(weight[i].divide(aa[i], BigDecimal.ROUND_HALF_UP)); + sum = sumW.divide(sum, BigDecimal.ROUND_HALF_UP); + sumW = null; + weight = null; + return sum; + } + + // Weighted harmonic mean of a 1D array of BigInteger, aa + public static BigDecimal harmonicMean(BigInteger[] aa, BigInteger[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + ArrayMaths am = new ArrayMaths(aa); + ArrayMaths wm = new ArrayMaths(ww); + return harmonicMean(am.getArray_as_BigDecimal(), wm.getArray_as_BigDecimal()); + } + + // Weighted harmonic mean of a 1D array of Complex, aa + public static Complex harmonicMean(Complex[] aa, Complex[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + Complex sum = Complex.zero(); + Complex sumW = Complex.zero(); + Complex[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumW = sumW.plus(weight[i]); + } + for(int i=0; i<n; i++)sum = sum.plus(weight[i].over(aa[i])); + return sumW.over(sum); + } + + // Weighted harmonic mean of a 1D array of doubles, aa + public static double harmonicMean(double[] aa, double[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + double sum = 0.0D; + double sumW = 0.0D; + double[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumW += weight[i]; + } + for(int i=0; i<n; i++)sum += weight[i]/aa[i]; + return sumW/sum; + } + + // Weighted harmonic mean of a 1D array of floats, aa + public static float harmonicMean(float[] aa, float[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + float sum = 0.0F; + float sumW = 0.0F; + float[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumW += weight[i]; + } + for(int i=0; i<n; i++)sum += weight[i]/aa[i]; + return sumW/sum; + } + + // GENERALIZED MEANS [POWER MEANS] (STATIC METHODS) + + // generalized mean of a 1D array of Complex, aa + public static Complex generalizedMean(Complex[] aa, double m){ + int n = aa.length; + Complex sum = Complex.zero(); + if(m==0.0D){ + for(int i=0; i<n; i++){ + sum = sum.plus(Complex.log(aa[i])); + } + return Complex.exp(sum); + } + else{ + for(int i=0; i<n; i++){ + sum = sum.plus(Complex.pow(aa[i],m)); + } + return Complex.pow(sum.over((double)n), 1.0D/m); + } + } + + // generalized mean of a 1D array of Complex, aa + public static Complex generalizedMean(Complex[] aa, Complex m){ + int n = aa.length; + Complex sum = Complex.zero(); + if(m.equals(Complex.zero())){ + for(int i=0; i<n; i++){ + sum = sum.plus(Complex.log(aa[i])); + } + return Complex.exp(sum); + } + else{ + for(int i=0; i<n; i++){ + sum = sum.plus(Complex.pow(aa[i],m)); + } + return Complex.pow(sum.over((double)n), Complex.plusOne().over(m)); + } + } + + // generalized mean of a 1D array of BigDecimal, aa + public static double generalizedMean(BigDecimal[] aa, double m){ + ArrayMaths am = new ArrayMaths(aa); + double[] dd = am.getArray_as_double(); + return generalizedMean(dd, m); + } + + // generalized mean of a 1D array of BigDecimal, aa + public static double generalizedMean(BigDecimal[] aa, BigDecimal m){ + ArrayMaths am = new ArrayMaths(aa); + double[] dd = am.getArray_as_double(); + return generalizedMean(dd, m.doubleValue()); + } + + // generalized mean of a 1D array of BigInteger, aa + public static double generalizedMean(BigInteger[] aa, double m){ + ArrayMaths am = new ArrayMaths(aa); + double[] dd = am.getArray_as_double(); + return generalizedMean(dd, m); + } + + // generalized mean of a 1D array of BigInteger, aa + public static double generalizedMean(BigInteger[] aa, BigInteger m){ + ArrayMaths am = new ArrayMaths(aa); + double[] dd = am.getArray_as_double(); + return generalizedMean(dd, m.doubleValue()); + } + + // generalized mean of a 1D array of doubles, aa + public static double generalizedMean(double[] aa, double m){ + int n = aa.length; + double sum=0.0D; + if(m==0){ + for(int i=0; i<n; i++){ + sum += Math.log(aa[i]); + } + return Math.exp(sum); + } + else{ + for(int i=0; i<n; i++){ + sum += Math.pow(aa[i],m); + } + return Math.pow(sum/((double)n), 1.0D/m); + } + } + + // generalized mean of a 1D array of floats, aa + public static float generalizedMean(float[] aa, float m){ + int n = aa.length; + float sum=0.0F; + if(m==0){ + for(int i=0; i<n; i++){ + sum += (float)Math.log(aa[i]); + } + return (float)Math.exp(sum); + } + else{ + for(int i=0; i<n; i++){ + sum += Math.pow(aa[i],m); + } + return (float)Math.pow(sum/((float)n), 1.0F/m); + } + } + + + // Generalised mean of a 1D array of Complex, aa + public static Complex generalisedMean(Complex[] aa, double m){ + int n = aa.length; + Complex sum = Complex.zero(); + if(m==0.0D){ + for(int i=0; i<n; i++){ + sum = sum.plus(Complex.log(aa[i])); + } + return Complex.exp(sum); + } + else{ + for(int i=0; i<n; i++){ + sum = sum.plus(Complex.pow(aa[i],m)); + } + return Complex.pow(sum.over((double)n), 1.0D/m); + } + } + + // Generalised mean of a 1D array of Complex, aa + public static Complex generalisedMean(Complex[] aa, Complex m){ + int n = aa.length; + Complex sum = Complex.zero(); + if(m.equals(Complex.zero())){ + for(int i=0; i<n; i++){ + sum = sum.plus(Complex.log(aa[i])); + } + return Complex.exp(sum); + } + else{ + for(int i=0; i<n; i++){ + sum = sum.plus(Complex.pow(aa[i],m)); + } + return Complex.pow(sum.over((double)n), Complex.plusOne().over(m)); + } + } + + // Generalised mean of a 1D array of BigDecimal, aa + public static double generalisedMean(BigDecimal[] aa, double m){ + ArrayMaths am = new ArrayMaths(aa); + double[] dd = am.getArray_as_double(); + return generalisedMean(dd, m); + } + + // Generalised mean of a 1D array of BigDecimal, aa + public static double generalisedMean(BigDecimal[] aa, BigDecimal m){ + ArrayMaths am = new ArrayMaths(aa); + double[] dd = am.getArray_as_double(); + return generalisedMean(dd, m.doubleValue()); + } + + // Generalised mean of a 1D array of BigInteger, aa + public static double generalisedMean(BigInteger[] aa, double m){ + ArrayMaths am = new ArrayMaths(aa); + double[] dd = am.getArray_as_double(); + return generalisedMean(dd, m); + } + + // Generalised mean of a 1D array of BigInteger, aa + public static double generalisedMean(BigInteger[] aa, BigInteger m){ + ArrayMaths am = new ArrayMaths(aa); + double[] dd = am.getArray_as_double(); + return generalisedMean(dd, m.doubleValue()); + } + + // Generalised mean of a 1D array of doubles, aa + public static double generalisedMean(double[] aa, double m){ + int n = aa.length; + double sum=0.0D; + if(m==0){ + for(int i=0; i<n; i++){ + sum += Math.log(aa[i]); + } + return Math.exp(sum); + } + else{ + for(int i=0; i<n; i++){ + sum += Math.pow(aa[i],m); + } + return Math.pow(sum/((double)n), 1.0D/m); + } + } + + // Generalised mean of a 1D array of floats, aa + public static float generalisedMean(float[] aa, float m){ + int n = aa.length; + float sum=0.0F; + if(m==0){ + for(int i=0; i<n; i++){ + sum += (float)Math.log(aa[i]); + } + return (float)Math.exp(sum); + } + else{ + for(int i=0; i<n; i++){ + sum += Math.pow(aa[i],m); + } + return (float)Math.pow(sum/((float)n), 1.0F/m); + } + } + + // WEIGHTED GENERALIZED MEANS + + // weighted generalized mean of a 1D array of Complex, aa + public static Complex generalisedMean(Complex[] aa, Complex[] ww, double m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + Complex sum = Complex.zero(); + Complex sumw = Complex.zero(); + Complex[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumw = sumw.plus(weight[i]); + } + + if(m==0.0D){ + for(int i=0; i<n; i++){ + sum = sum.plus(Complex.log(weight[i].times(aa[i])).over(sumw)); + } + return Complex.exp(sum); + } + else{ + for(int i=0; i<n; i++){ + sum = sum.plus(weight[i].times(Complex.pow(aa[i],m))); + } + return Complex.pow(sum.over(sumw), 1.0D/m); + } + } + + // weighted generalized mean of a 1D array of Complex, aa + public static Complex generalisedMean(Complex[] aa, Complex[] ww, Complex m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + Complex sum = Complex.zero(); + Complex sumw = Complex.zero(); + Complex[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumw = sumw.plus(weight[i]); + } + + if(m.equals(Complex.zero())){ + for(int i=0; i<n; i++){ + sum = sum.plus(Complex.log(weight[i].times(aa[i])).over(sumw)); + } + return Complex.exp(sum); + } + else{ + for(int i=0; i<n; i++){ + sum = sum.plus(weight[i].times(Complex.pow(aa[i],m))); + } + return Complex.pow(sum.over(sumw), Complex.plusOne().over(m)); + } + } + + // weighted generalized mean of a 1D array of BigDecimal, aa + public static double generalisedMean(BigDecimal[] aa, BigDecimal[] ww, double m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + ArrayMaths am1 = new ArrayMaths(aa); + double[] dd = am1.getArray_as_double(); + ArrayMaths am2 = new ArrayMaths(ww); + double[] wd = am2.getArray_as_double(); + return generalisedMean(dd, wd, m); + } + + // weighted generalized mean of a 1D array of BigDecimal, aa + public static double generalisedMean(BigDecimal[] aa, BigDecimal[] ww, BigDecimal m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + ArrayMaths am1 = new ArrayMaths(aa); + double[] dd = am1.getArray_as_double(); + ArrayMaths am2 = new ArrayMaths(ww); + double[] wd = am2.getArray_as_double(); + return generalisedMean(dd, wd, m.doubleValue()); + } + + // weighted generalized mean of a 1D array of BigInteger, aa + public static double generalisedMean(BigInteger[] aa, BigInteger[] ww, double m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + ArrayMaths am1 = new ArrayMaths(aa); + double[] dd = am1.getArray_as_double(); + ArrayMaths am2 = new ArrayMaths(ww); + double[] wd = am2.getArray_as_double(); + return generalisedMean(dd, wd, m); + } + + // weighted generalized mean of a 1D array of BigInteger, aa + public static double generalisedMean(BigInteger[] aa, BigInteger[] ww, BigInteger m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + ArrayMaths am1 = new ArrayMaths(aa); + double[] dd = am1.getArray_as_double(); + ArrayMaths am2 = new ArrayMaths(ww); + double[] wd = am2.getArray_as_double(); + return generalisedMean(dd, wd, m.doubleValue()); + } + + // weighted generalized mean of a 1D array of doubles, aa + public static double generalisedMean(double[] aa, double[] ww, double m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + double sum=0.0D; + double sumw=0.0D; + double[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumw += weight[i]; + } + + if(m==0){ + for(int i=0; i<n; i++){ + sum += Math.log(aa[i]*weight[i]/sumw); + } + return Math.exp(sum); + } + else{ + for(int i=0; i<n; i++){ + sum += weight[i]*Math.pow(aa[i],m); + } + return Math.pow(sum/sumw, 1.0D/m); + } + } + + // weighted generalized mean of a 1D array of floats, aa + public static float generalisedMean(float[] aa, float[] ww, float m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + float sum=0.0F; + float sumw=0.0F; + float[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumw += weight[i]; + } + if(m==0){ + for(int i=0; i<n; i++){ + sum += (float)Math.log(aa[i]); + } + return (float)Math.exp(sum); + } + else{ + for(int i=0; i<n; i++){ + sum += Math.pow(aa[i],m); + } + return (float)Math.pow(sum/sumw, 1.0F/m); + } + } + + + // weighted generalised mean of a 1D array of Complex, aa + public static Complex weightedGeneralisedMean(Complex[] aa, Complex[] ww, double m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + return generalisedMean(aa, ww, m); + } + + // weighted generalised mean of a 1D array of Complex, aa + public static Complex weightedGeneralisedMean(Complex[] aa, Complex[] ww, Complex m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + return generalisedMean(aa, ww, m); + } + + // weighted generalised mean of a 1D array of BigDecimal, aa + public static double weightedGeneralisedMean(BigDecimal[] aa, BigDecimal[] ww, double m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + return generalisedMean(aa, ww, m); + } + + // weighted generalised mean of a 1D array of BigDecimal, aa + public static double weightedGeneralisedMean(BigDecimal[] aa, BigDecimal[] ww, BigDecimal m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + return generalisedMean(aa, ww, m); + } + + // weighted generalised mean of a 1D array of BigInteger, aa + public static double weightedGeneralisedMean(BigInteger[] aa, BigInteger[] ww, double m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + return generalisedMean(aa, ww, m); + } + + // weighted generalised mean of a 1D array of BigInteger, aa + public static double weightedGeneralisedMean(BigInteger[] aa, BigInteger[] ww, BigInteger m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + return generalisedMean(aa, ww, m); + } + + // weighted generalised mean of a 1D array of doubles, aa + public static double weightedGeneralisedMean(double[] aa, double[] ww, double m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + return generalisedMean(aa, ww, m); + } + + // weighted generalised mean of a 1D array of floats, aa + public static float weightedGeneralisedMean(float[] aa, float[] ww, float m){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + return generalisedMean(aa, ww, m); + } + + + + + // INTERQUARTILE MEANS + + // Interquartile mean of a 1D array of BigDecimal, aa + public static BigDecimal interQuartileMean(BigDecimal[] aa){ + int n = aa.length; + if(n<4)throw new IllegalArgumentException("At least 4 array elements needed"); + ArrayMaths am = new ArrayMaths(aa); + ArrayMaths as = am.sort(); + BigDecimal[] bb = as.getArray_as_BigDecimal(); + BigDecimal sum = BigDecimal.ZERO; + for(int i=n/4; i<3*n/4; i++)sum = sum.add(bb[i]); + sum = sum.multiply(new BigDecimal(2.0D/(double)n)); + bb = null; + return sum; + } + + // Interquartile mean of a 1D array of BigInteger, aa + public static BigDecimal interQuartileMean(BigInteger[] aa){ + int n = aa.length; + if(n<4)throw new IllegalArgumentException("At least 4 array elements needed"); + ArrayMaths am = new ArrayMaths(aa); + ArrayMaths as = am.sort(); + BigDecimal[] bb = as.getArray_as_BigDecimal(); + BigDecimal sum = BigDecimal.ZERO; + for(int i=n/4; i<3*n/4; i++)sum = sum.add(bb[i]); + sum = sum.multiply(new BigDecimal(2.0D/(double)n)); + bb = null; + return sum; + } + + // Interquartile mean of a 1D array of doubles, aa + public static double interQuartileMean(double[] aa){ + int n = aa.length; + if(n<4)throw new IllegalArgumentException("At least 4 array elements needed"); + double[] bb = Fmath.selectionSort(aa); + double sum = 0.0D; + for(int i=n/4; i<3*n/4; i++)sum += bb[i]; + return 2.0*sum/(double)(n); + } + + // Interquartile mean of a 1D array of floats, aa + public static float interQuartileMean(float[] aa){ + int n = aa.length; + if(n<4)throw new IllegalArgumentException("At least 4 array elements needed"); + float[] bb = Fmath.selectionSort(aa); + float sum = 0.0F; + for(int i=n/4; i<3*n/4; i++)sum += bb[i]; + return 2.0F*sum/(float)(n); + } + + // ROOT MEAN SQUARES + + // Root mean square (rms) of a 1D array of doubles, aa + public static double rms(double[] aa){ + int n = aa.length; + double sum=0.0D; + for(int i=0; i<n; i++){ + sum+=aa[i]*aa[i]; + } + return Math.sqrt(sum/((double)n)); + } + + // Root mean square (rms) of a 1D array of floats, aa + public static float rms(float[] aa){ + int n = aa.length; + float sum = 0.0F; + for(int i=0; i<n; i++){ + sum+=aa[i]*aa[i]; + } + sum /= (float)n; + + return (float)Math.sqrt(sum); + } + + // Root mean square (rms) of a 1D array of BigDecimal, aa + public static double rms(BigDecimal[] aa){ + int n = aa.length; + BigDecimal sum = BigDecimal.ZERO; + for(int i=0; i<n; i++){ + sum = sum.add(aa[i].multiply(aa[i])); + } + sum = sum.divide((new BigDecimal(n)), BigDecimal.ROUND_HALF_UP); + double ret = Math.sqrt(sum.doubleValue()); + sum = null; + return ret; + } + + // Root mean square (rms) of a 1D array of BigInteger, aa + public static double rms(BigInteger[] aa){ + int n = aa.length; + BigDecimal sum = BigDecimal.ZERO; + BigDecimal bd = BigDecimal.ZERO; + for(int i=0; i<n; i++){ + bd = new BigDecimal(aa[i]); + sum = sum.add(bd.multiply(bd)); + } + sum = sum.divide((new BigDecimal(n)), BigDecimal.ROUND_HALF_UP); + double ret = Math.sqrt(sum.doubleValue()); + bd = null; + sum = null; + return ret; + } + + // WEIGHTED ROOT MEAN SQUARES + + // Weighted root mean square (rms) of a 1D array of doubles, aa + public static double rms(double[] aa, double[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + double sumw =0.0D; + double[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumw += weight[i]; + } + double sum=0.0D; + for(int i=0; i<n; i++){ + sum += weight[i]*aa[i]*aa[i]; + } + return Math.sqrt(sum/sumw); + } + + // Weighted root mean square (rms) of a 1D array of floats, aa + public static float rms(float[] aa, float[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + double sumw =0.0F; + float[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumw += weight[i]; + } + float sum=0.0F; + for(int i=0; i<n; i++){ + sum += weight[i]*aa[i]*aa[i]; + } + return (float)Math.sqrt(sum/sumw); + } + + // Weighted root mean square (rms) of a 1D array of BigDecimal, aa + public static double rms(BigDecimal[] aa, BigDecimal[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + BigDecimal sumw = BigDecimal.ZERO; + BigDecimal[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumw = sumw.add(weight[i]); + } + + BigDecimal sum = BigDecimal.ZERO; + for(int i=0; i<n; i++){ + sum = sum.add((aa[i].multiply(aa[i])).multiply(weight[i])); + } + sum = sum.divide(sumw, BigDecimal.ROUND_HALF_UP); + double ret = Math.sqrt(sum.doubleValue()); + sum = null; + weight = null; + return ret; + } + + // Weighted root mean square (rms) of a 1D array of BigInteger, aa + public static double rms(BigInteger[] aa, BigInteger[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + + + ArrayMaths amaa = new ArrayMaths(aa); + ArrayMaths amww = new ArrayMaths(ww); + return rms(amaa.array_as_BigDecimal(), amww.array_as_BigDecimal()); + } + + // MEDIANS + + // Median of a 1D array of BigDecimal, aa + public static BigDecimal median(BigDecimal[] aa){ + int n = aa.length; + int nOverTwo = n/2; + BigDecimal med = BigDecimal.ZERO; + ArrayMaths bm = new ArrayMaths(aa); + ArrayMaths sm = bm.sort(); + BigDecimal[] bb = bm.getArray_as_BigDecimal(); + if(Fmath.isOdd(n)){ + med = bb[nOverTwo]; + } + else{ + med = (bb[nOverTwo-1].add(bb[nOverTwo])).divide(new BigDecimal(2.0D), BigDecimal.ROUND_HALF_UP); + } + bb = null; + return med; + } + + // Median of a 1D array of BigInteger, aa + public static BigInteger median(BigInteger[] aa){ + int n = aa.length; + int nOverTwo = n/2; + BigInteger med = BigInteger.ZERO; + ArrayMaths bm = new ArrayMaths(aa); + ArrayMaths sm = bm.sort(); + BigInteger[] bb = bm.getArray_as_BigInteger(); + if(Fmath.isOdd(n)){ + med = bb[nOverTwo]; + } + else{ + med = (bb[nOverTwo-1].add(bb[nOverTwo])).divide(new BigInteger("2")); + } + bb = null; + return med; + } + + // Median of a 1D array of doubles, aa + public static double median(double[] aa){ + int n = aa.length; + int nOverTwo = n/2; + double med = 0.0D; + double[] bb = Fmath.selectionSort(aa); + if(Fmath.isOdd(n)){ + med = bb[nOverTwo]; + } + else{ + med = (bb[nOverTwo-1]+bb[nOverTwo])/2.0D; + } + + return med; + } + + + // Median of a 1D array of floats, aa + public static float median(float[] aa){ + int n = aa.length; + int nOverTwo = n/2; + float med = 0.0F; + float[] bb = Fmath.selectionSort(aa); + if(Fmath.isOdd(n)){ + med = bb[nOverTwo]; + } + else{ + med = (bb[nOverTwo-1]+bb[nOverTwo])/2.0F; + } + + return med; + } + + // Median of a 1D array of int, aa + public static double median(int[] aa){ + int n = aa.length; + int nOverTwo = n/2; + double med = 0.0D; + int[] bb = Fmath.selectionSort(aa); + if(Fmath.isOdd(n)){ + med = (double)bb[nOverTwo]; + } + else{ + med = (double)(bb[nOverTwo-1]+bb[nOverTwo])/2.0D; + } + + return med; + } + + // Median of a 1D array of long, aa + public static double median(long[] aa){ + int n = aa.length; + int nOverTwo = n/2; + double med = 0.0D; + long[] bb = Fmath.selectionSort(aa); + if(Fmath.isOdd(n)){ + med = (double)bb[nOverTwo]; + } + else{ + med = (double)(bb[nOverTwo-1]+bb[nOverTwo])/2.0D; + } + + return med; + } + + + // STANDARD DEVIATIONS (STATIC METHODS) + + // Standard deviation of a 1D array of BigDecimals, aa + public static double standardDeviation(BigDecimal[] aa){ + return Math.sqrt(Stat.variance(aa).doubleValue()); + } + + // Standard deviation of a 1D array of BigIntegers, aa + public static double standardDeviation(BigInteger[] aa){ + return Math.sqrt(Stat.variance(aa).doubleValue()); + } + + // Standard deviation of a 1D array of Complex, aa + public static Complex standardDeviation(Complex[] aa){ + return Complex.sqrt(Stat.variance(aa)); + } + + // Standard deviation of a 1D array of Complex, aa, conjugate formula + public static double standardDeviationConjugateCalcn(Complex[] aa){ + return Math.sqrt(Stat.varianceConjugateCalcn(aa)); + } + + // Standard deviation of the moduli of a 1D array of Complex aa + public static double standardDeviationModuli(Complex[] aa){ + ArrayMaths am = new ArrayMaths(aa); + double[] rl = am.array_as_modulus_of_Complex(); + double standardDeviation = Stat.standardDeviation(rl); + return standardDeviation; + } + + // Standard deviation of the real parts of a 1D array of Complex aa + public static double standardDeviationRealParts(Complex[] aa){ + ArrayMaths am = new ArrayMaths(aa); + double[] rl = am.array_as_real_part_of_Complex(); + double standardDeviation = Stat.standardDeviation(rl); + return standardDeviation; + } + + // Standard deviation of the imaginary parts of a 1D array of Complex aa + public static double standardDeviationImaginaryParts(Complex[] aa){ + ArrayMaths am = new ArrayMaths(aa); + double[] im = am.array_as_imaginary_part_of_Complex(); + double standardDeviation = Stat.standardDeviation(im); + return standardDeviation; + } + + // Standard deviation of a 1D array of doubles, aa + public static double standardDeviation(double[] aa){ + return Math.sqrt(Stat.variance(aa)); + } + + // Standard deviation of a 1D array of floats, aa + public static float standardDeviation(float[] aa){ + return (float)Math.sqrt(Stat.variance(aa)); + } + + // Standard deviation of a 1D array of int, aa + public static double standardDeviation(int[] aa){ + return Math.sqrt(Stat.variance(aa)); + } + + // Standard deviation of a 1D array of long, aa + public static double standardDeviation(long[] aa){ + return Math.sqrt(Stat.variance(aa)); + } + + // Weighted standard deviation of a 1D array of Complex, aa + public static Complex standardDeviation(Complex[] aa, Complex[] ww){ + if(aa.length!=ww.length)throw new IllegalArgumentException("length of variable array, " + aa.length + " and length of weight array, " + ww.length + " are different"); + return Complex.sqrt(Stat.variance(aa, ww)); + } + + // Weighted standard deviation of a 1D array of Complex, aa, using conjugate formula + public static double standardDeviationConjugateCalcn(Complex[] aa, Complex[] ww){ + if(aa.length!=ww.length)throw new IllegalArgumentException("length of variable array, " + aa.length + " and length of weight array, " + ww.length + " are different"); + return Math.sqrt(Stat.varianceConjugateCalcn(aa, ww)); + } + + // Weighted standard deviation of the moduli of a 1D array of Complex aa + public static double standardDeviationModuli(Complex[] aa, Complex[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + ArrayMaths am = new ArrayMaths(aa); + double[] rl = am.array_as_modulus_of_Complex(); + ArrayMaths wm = new ArrayMaths(ww); + double[] wt = wm.array_as_modulus_of_Complex(); + double standardDeviation = Stat.standardDeviation(rl, wt); + return standardDeviation; + } + + // Weighted standard deviation of the real parts of a 1D array of Complex aa + public static double standardDeviationRealParts(Complex[] aa, Complex[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + ArrayMaths am = new ArrayMaths(aa); + double[] rl = am.array_as_real_part_of_Complex(); + ArrayMaths wm = new ArrayMaths(ww); + double[] wt = wm.array_as_real_part_of_Complex(); + double standardDeviation = Stat.standardDeviation(rl, wt); + return standardDeviation; + } + + // Weighted standard deviation of the imaginary parts of a 1D array of Complex aa + public static double standardDeviationImaginaryParts(Complex[] aa, Complex[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + ArrayMaths am = new ArrayMaths(aa); + double[] im = am.array_as_imaginary_part_of_Complex(); + ArrayMaths wm = new ArrayMaths(ww); + double[] wt = wm.array_as_imaginary_part_of_Complex(); + double standardDeviation = Stat.standardDeviation(im, wt); + return standardDeviation; + } + + + // Weighted standard deviation of a 1D array of BigDecimal, aa + public static double standardDeviation(BigDecimal[] aa, BigDecimal[] ww){ + if(aa.length!=ww.length)throw new IllegalArgumentException("length of variable array, " + aa.length + " and length of weight array, " + ww.length + " are different"); + return Math.sqrt(Stat.variance(aa, ww).doubleValue()); + } + + // Weighted standard deviation of a 1D array of BigInteger, aa + public static double standardDeviation(BigInteger[] aa, BigInteger[] ww){ + if(aa.length!=ww.length)throw new IllegalArgumentException("length of variable array, " + aa.length + " and length of weight array, " + ww.length + " are different"); + return Math.sqrt(Stat.variance(aa, ww).doubleValue()); + } + + // Weighted standard deviation of a 1D array of doubles, aa + public static double standardDeviation(double[] aa, double[] ww){ + if(aa.length!=ww.length)throw new IllegalArgumentException("length of variable array, " + aa.length + " and length of weight array, " + ww.length + " are different"); + return Math.sqrt(Stat.variance(aa, ww)); + } + + // Weighted standard deviation of a 1D array of floats, aa + public static float standardDeviation(float[] aa, float[] ww){ + if(aa.length!=ww.length)throw new IllegalArgumentException("length of variable array, " + aa.length + " and length of weight array, " + ww.length + " are different"); + return (float)Math.sqrt(Stat.variance(aa, ww)); + } + + + // VOLATILITIES + + // volatility log (BigDecimal) + public static double volatilityLogChange(BigDecimal[] array){ + int n = array.length-1; + double[] change = new double[n]; + for(int i=0; i<n; i++)change[i] = Math.log((array[i+1].divide(array[i], BigDecimal.ROUND_HALF_UP)).doubleValue()); + return Stat.standardDeviation(change); + } + + // volatility log (BigInteger) + public static double volatilityLogChange(BigInteger[] array){ + int n = array.length-1; + double[] change = new double[n]; + for(int i=0; i<n; i++)change[i] = Math.log(((new BigDecimal(array[i+1])).divide( new BigDecimal(array[i]), BigDecimal.ROUND_HALF_UP)).doubleValue()); + return Stat.standardDeviation(change); + } + + // volatility log (doubles) + public static double volatilityLogChange(double[] array){ + int n = array.length-1; + double[] change = new double[n]; + for(int i=0; i<n; i++)change[i] = Math.log(array[i+1]/array[i]); + return Stat.standardDeviation(change); + } + + // volatility log (floats) + public static float volatilityLogChange(float[] array){ + int n = array.length-1; + float[] change = new float[n]; + for(int i=0; i<n; i++)change[i] = (float)Math.log(array[i+1]/array[i]); + return Stat.standardDeviation(change); + } + + // volatility percentage (BigDecimal) + public static double volatilityPerCentChange(BigDecimal[] array){ + int n = array.length-1; + double[] change = new double[n]; + for(int i=0; i<n; i++)change[i] = ((array[i+1].add(array[i])).multiply((new BigDecimal(100.0D)).divide(array[i], BigDecimal.ROUND_HALF_UP))).doubleValue(); + return Stat.standardDeviation(change); + } + + // volatility percentage (Biginteger) + public static double volatilityPerCentChange(BigInteger[] array){ + int n = array.length-1; + double[] change = new double[n]; + ArrayMaths am = new ArrayMaths(array); + BigDecimal[] bd = am.getArray_as_BigDecimal(); + for(int i=0; i<n; i++)change[i] = ((bd[i+1].add(bd[i])).multiply((new BigDecimal(100.0D)).divide(bd[i], BigDecimal.ROUND_HALF_UP))).doubleValue(); + bd = null; + return Stat.standardDeviation(change); + } + + // volatility percentage (double) + public static double volatilityPerCentChange(double[] array){ + int n = array.length-1; + double[] change = new double[n]; + for(int i=0; i<n; i++)change[i] = (array[i+1] - array[i])*100.0D/array[i]; + return Stat.standardDeviation(change); + } + + // volatility percentage (float) + public static double volatilityPerCentChange(float[] array){ + int n = array.length-1; + float[] change = new float[n]; + for(int i=0; i<n; i++)change[i] = (array[i+1] - array[i])*100.0F/array[i]; + return Stat.standardDeviation(change); + } + + + // COEFFICIENT OF VARIATION + + // Coefficient of variation of an array of BigInteger + public static double coefficientOfVariation(BigInteger[] array){ + return 100.0D*Stat.standardDeviation(array)/Math.abs(Stat.mean(array).doubleValue()); + } + + // Coefficient of variation of an array of BigDecimals + public static double coefficientOfVariation(BigDecimal[] array){ + return 100.0D*Stat.standardDeviation(array)/Math.abs(Stat.mean(array).doubleValue()); + } + + // Coefficient of variation of an array of doubles + public static double coefficientOfVariation(double[] array){ + return 100.0D*Stat.standardDeviation(array)/Math.abs(Stat.mean(array)); + } + + // Coefficient of variation of an array of float + public static float coefficientOfVariation(float[] array){ + return 100.0F*Stat.standardDeviation(array)/Math.abs(Stat.mean(array)); + } + + + // WEIGHTED COEFFICIENT OF VARIATION + + // Weighted coefficient of variation of an array of BigInteger + public static double coefficientOfVariation(BigInteger[] array, BigInteger[] weight){ + int n = array.length; + if(n!=weight.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + weight.length + " are different"); + + return 100.0D*Stat.standardDeviation(array, weight)/Math.abs(Stat.mean(array, weight).doubleValue()); + } + + // Weighted coefficient of variation of an array of BigDecimals + public static double coefficientOfVariation(BigDecimal[] array, BigDecimal[] weight){ + int n = array.length; + if(n!=weight.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + weight.length + " are different"); + + return 100.0D*Stat.standardDeviation(array, weight)/Math.abs(Stat.mean(array, weight).doubleValue()); + } + + // Weighted coefficient of variation of an array of doubles + public static double coefficientOfVariation(double[] array, double[] weight){ + int n = array.length; + if(n!=weight.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + weight.length + " are different"); + + return 100.0D*Stat.standardDeviation(array, weight)/Math.abs(Stat.mean(array, weight)); + } + + // Weighted coefficient of variation of an array of float + public static float coefficientOfVariation(float[] array, float[] weight){ + int n = array.length; + if(n!=weight.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + weight.length + " are different"); + + return 100.0F*Stat.standardDeviation(array, weight)/Math.abs(Stat.mean(array, weight)); + } + + + //STANDARDIZATION + // Standardization of an array of doubles to a mean of 0 and a standard deviation of 1 + public static double[] standardize(double[] aa){ + double mean0 = Stat.mean(aa); + double sd0 = Stat.standardDeviation(aa); + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = (aa[i] - mean0)/sd0; + } + + return bb; + } + + public static double[] standardise(double[] aa){ + return Stat.standardize(aa); + } + + // Standardization of an array of floats to a mean of 0 and a standard deviation of 1 + public static float[] standardize(float[] aa){ + float mean0 = Stat.mean(aa); + float sd0 = Stat.standardDeviation(aa); + int n = aa.length; + float[] bb = new float[n]; + for(int i=0; i<n; i++){ + bb[i] = (aa[i] - mean0)/sd0; + } + + return bb; + } + + public static float[] standardise(float[] aa){ + return Stat.standardize(aa); + } + + // Standardization of an array of longs to a mean of 0 and a standard deviation of 1 + // converts to double + public static double[] standardize(long[] aa){ + double mean0 = Stat.mean(aa); + double sd0 = Stat.standardDeviation(aa); + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = (aa[i] - mean0)/sd0; + } + + return bb; + } + + public static double[] standardise(long[] aa){ + return Stat.standardize(aa); + } + + // Standardization of an array of ints to a mean of 0 and a standard deviation of 1 + // converts to double + public static double[] standardize(int[] aa){ + double mean0 = Stat.mean(aa); + double sd0 = Stat.standardDeviation(aa); + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = (aa[i] - mean0)/sd0; + } + + return bb; + } + + public static double[] standardise(int[] aa){ + return Stat.standardize(aa); + } + + // Standardization of an array of BigDecimals to a mean of 0 and a standard deviation of 1 + // converts to double + public static double[] standardize(BigDecimal[] aa){ + double mean0 = Stat.mean(aa).doubleValue(); + double sd0 = Stat.standardDeviation(aa); + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = (aa[i].doubleValue() - mean0)/sd0; + } + + return bb; + } + + public static double[] standardise(BigDecimal[] aa){ + return Stat.standardize(aa); + } + + // Standardization of an array of BigIntegers to a mean of 0 and a standard deviation of 1 + // converts to double + public static double[] standardize(BigInteger[] aa){ + ArrayMaths am = new ArrayMaths(aa); + BigDecimal[] bd = am.getArray_as_BigDecimal(); + + return Stat.standardize(bd); + } + + public static double[] standardise(BigInteger[] aa){ + return Stat.standardize(aa); + } + + // SCALING DATA + // Scale an array of doubles to a new mean and new standard deviation + public static double[] scale(double[] aa, double mean, double sd){ + double[] bb = Stat.standardize(aa); + int n = aa.length; + for(int i=0; i<n; i++){ + bb[i] = bb[i]*sd + mean; + } + + return bb; + } + + // Scale an array of floats to a new mean and new standard deviation + public static float[] scale(float[] aa, float mean, float sd){ + float[] bb = Stat.standardize(aa); + int n = aa.length; + for(int i=0; i<n; i++){ + bb[i] = bb[i]*sd + mean; + } + + return bb; + } + + // Scale an array of longs to a new mean and new standard deviation + public static double[] scale(long[] aa, double mean, double sd){ + double[] bb = Stat.standardize(aa); + int n = aa.length; + for(int i=0; i<n; i++){ + bb[i] = bb[i]*sd + mean; + } + + return bb; + } + + // Scale an array of longs to a new mean and new standard deviation + public static double[] scale(int[] aa, double mean, double sd){ + double[] bb = Stat.standardize(aa); + int n = aa.length; + for(int i=0; i<n; i++){ + bb[i] = bb[i]*sd + mean; + } + + return bb; + } + + // Scale an array of BigDecimals to a new mean and new standard deviation + public static double[] scale(BigDecimal[] aa, double mean, double sd){ + double[] bb = Stat.standardize(aa); + int n = aa.length; + for(int i=0; i<n; i++){ + bb[i] = bb[i]*sd + mean; + } + + return bb; + } + + // Scale an array of BigIntegers to a new mean and new standard deviation + public static double[] scale(BigInteger[] aa, double mean, double sd){ + ArrayMaths am = new ArrayMaths(aa); + BigDecimal[] bd = am.getArray_as_BigDecimal(); + + return Stat.scale(bd, mean, sd); + } + + + // SKEWNESS + // Static Methods + // Moment skewness of a 1D array of doubles + public static double momentSkewness(double[] aa){ + int n = aa.length; + double denom = (double)(n-1); + if(Stat.nFactorOptionS)denom = (double)n; + double sum = 0.0D; + double mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + sum+=Math.pow((aa[i]-mean), 3); + } + sum = sum/denom; + return sum/Math.pow(Stat.standardDeviation(aa), 3); + } + + + // Moment skewness of a 1D array of floats + public static float momentSkewness(float[] aa){ + int n = aa.length; + float denom = (float)(n-1); + if(Stat.nFactorOptionS)denom = (float)n; + float sum = 0.0F; + float mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + sum+=Math.pow((aa[i]-mean), 3); + } + sum = sum/denom; + return sum/((float)Math.pow(Stat.standardDeviation(aa), 3)); + } + + // Moment skewness of a 1D array of BigDecimal + public static double momentSkewness(BigDecimal[] aa){ + int n = aa.length; + double denom = (double)(n-1); + if(Stat.nFactorOptionS)denom = (double)n; + BigDecimal sum = BigDecimal.ZERO; + BigDecimal mean = Stat.mean(aa); + double sd = Stat.standardDeviation(aa); + for(int i=0; i<n; i++){ + BigDecimal hold = aa[i].subtract(mean); + sum = sum.add(hold.multiply(hold.multiply(hold)) ); + } + sum = sum.multiply(new BigDecimal(1.0/denom)); + return sum.doubleValue()/Math.pow(sd, 3); + } + + // Moment skewness of a 1D array of long + public static double momentSkewness(long[] aa){ + int n = aa.length; + double denom = (double)(n-1); + if(Stat.nFactorOptionS)denom = (double)n; + double sum = 0.0D; + double mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + sum+=Math.pow((aa[i]-mean), 3); + } + sum = sum/denom; + return sum/Math.pow(Stat.standardDeviation(aa), 3); + } + + // Moment skewness of a 1D array of int + public static double momentSkewness(int[] aa){ + int n = aa.length; + double denom = (double)(n-1); + if(Stat.nFactorOptionS)denom = (double)n; + double sum = 0.0D; + double mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + sum+=Math.pow((aa[i]-mean), 3); + } + sum = sum/denom; + return sum/Math.pow(Stat.standardDeviation(aa), 3); + } + + + + + // Median skewness of a 1D array of doubles + public static double medianSkewness(double[] aa){ + double mean = Stat.mean(aa); + double median = Stat.median(aa); + double sd = Stat.standardDeviation(aa); + return 3.0*(mean - median)/sd; + } + + // Median skewness of a 1D array of floats + public static float medianSkewness(float[] aa){ + float mean = Stat.mean(aa); + float median = Stat.median(aa); + float sd = Stat.standardDeviation(aa); + return 3.0F*(mean - median)/sd; + } + + // Median skewness of a 1D array of BigDecimal + public static double medianSkewness(BigDecimal[] aa){ + BigDecimal mean = Stat.mean(aa); + BigDecimal median = Stat.median(aa); + double sd = Stat.standardDeviation(aa); + return 3.0*(mean.subtract(median)).doubleValue()/sd; + } + + // Median skewness of a 1D array of long + public static double medianSkewness(long[] aa){ + double mean = Stat.mean(aa); + double median = Stat.median(aa); + double sd = Stat.standardDeviation(aa); + return 3.0*(mean - median)/sd; + } + + // Median skewness of a 1D array of int + public static double medianSkewness(int[] aa){ + double mean = Stat.mean(aa); + double median = Stat.median(aa); + double sd = Stat.standardDeviation(aa); + return 3.0*(mean - median)/sd; + } + + + // Quartile skewness of a 1D array of double + public static double quartileSkewness(double[] aa){ + int n = aa.length; + double median50 = Stat.median(aa); + int start1 = 0; + int start2 = 0; + int end1 = n/2 - 1; + int end2 = n-1; + if(Fmath.isOdd(n)){ + start2 = end1 + 2; + } + else{ + start2 = end1 + 1; + } + ArrayMaths am = new ArrayMaths(aa); + double[] first = am.subarray_as_double(start1, end1); + double[] last = am.subarray_as_double(start2, end2); + double median25 = Stat.median(first); + double median75 = Stat.median(last); + + return (median25 - 2.0*median50 + median75)/(median75 - median25); + } + + // Quartile skewness of a 1D array of float + public static float quartileSkewness(float[] aa){ + int n = aa.length; + float median50 = Stat.median(aa); + int start1 = 0; + int start2 = 0; + int end1 = n/2 - 1; + int end2 = n-1; + if(Fmath.isOdd(n)){ + start2 = end1 + 2; + } + else{ + start2 = end1 + 1; + } + ArrayMaths am = new ArrayMaths(aa); + float[] first = am.subarray_as_float(start1, end1); + float[] last = am.subarray_as_float(start2, end2); + float median25 = Stat.median(first); + float median75 = Stat.median(last); + + return (median25 - 2.0F*median50 + median75)/(median75 - median25); + } + + + // Quartile skewness of a 1D array of BigDecimal + public static BigDecimal quartileSkewness(BigDecimal[] aa){ + int n = aa.length; + BigDecimal median50 = Stat.median(aa); + int start1 = 0; + int start2 = 0; + int end1 = n/2 - 1; + int end2 = n-1; + if(Fmath.isOdd(n)){ + start2 = end1 + 2; + } + else{ + start2 = end1 + 1; + } + ArrayMaths am = new ArrayMaths(aa); + BigDecimal[] first = am.subarray_as_BigDecimal(start1, end1); + BigDecimal[] last = am.subarray_as_BigDecimal(start2, end2); + BigDecimal median25 = Stat.median(first); + BigDecimal median75 = Stat.median(last); + BigDecimal ret1 = (median25.subtract(median50.multiply(new BigDecimal(2.0)))).add(median75); + BigDecimal ret2 = median75.subtract(median25); + BigDecimal ret = ret1.divide(ret2,BigDecimal.ROUND_HALF_UP); + first = null; + last = null; + median25 = null; + median50 = null; + median75 = null; + ret1 = null; + ret2 = null; + return ret; + } + + // Quartile skewness of a 1D array of BigInteger + public static BigDecimal quartileSkewness(BigInteger[] aa){ + ArrayMaths am = new ArrayMaths(aa); + BigDecimal[] bd = am.array_as_BigDecimal(); + return Stat.quartileSkewness(bd); + } + + + // Quartile skewness of a 1D array of long + public static double quartileSkewness(long[] aa){ + int n = aa.length; + double median50 = Stat.median(aa); + int start1 = 0; + int start2 = 0; + int end1 = n/2 - 1; + int end2 = n-1; + if(Fmath.isOdd(n)){ + start2 = end1 + 2; + } + else{ + start2 = end1 + 1; + } + ArrayMaths am = new ArrayMaths(aa); + double[] first = am.subarray_as_double(start1, end1); + double[] last = am.subarray_as_double(start2, end2); + double median25 = Stat.median(first); + double median75 = Stat.median(last); + + return (median25 - 2.0*median50 + median75)/(median75 - median25); + } + + // Quartile skewness of a 1D array of int + public static double quartileSkewness(int[] aa){ + int n = aa.length; + double median50 = Stat.median(aa); + int start1 = 0; + int start2 = 0; + int end1 = n/2 - 1; + int end2 = n-1; + if(Fmath.isOdd(n)){ + start2 = end1 + 2; + } + else{ + start2 = end1 + 1; + } + ArrayMaths am = new ArrayMaths(aa); + double[] first = am.subarray_as_double(start1, end1); + double[] last = am.subarray_as_double(start2, end2); + double median25 = Stat.median(first); + double median75 = Stat.median(last); + + return (median25 - 2.0*median50 + median75)/(median75 - median25); + } + + + + // KURTOSIS + // Static Methods + // Kutosis of a 1D array of doubles + public static double kurtosis(double[] aa){ + int n = aa.length; + double denom = (double)(n-1); + if(Stat.nFactorOptionS)denom = (double)n; + double sum=0.0D; + double mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + sum+=Math.pow((aa[i]-mean), 4); + } + sum = sum/denom; + return sum/Fmath.square(Stat.variance(aa)); + } + + public static double curtosis(double[] aa){ + return Stat.kurtosis(aa); + } + + // Kutosis excess of a 1D array of doubles + public static double kurtosisExcess(double[] aa){ + return Stat.kurtosis(aa) - 3.0D; + } + + public static double curtosisExcess(double[] aa){ + return Stat.kurtosisExcess(aa); + } + + public static double excessKurtosis(double[] aa){ + return Stat.kurtosisExcess(aa); + } + + public static double excessCurtosis(double[] aa){ + return Stat.kurtosisExcess(aa); + } + + // Kutosis of a 1D array of floats + public static float kurtosis(float[] aa){ + int n = aa.length; + float denom = (float)(n-1); + if(Stat.nFactorOptionS)denom = (float)n; + float sum=0.0F; + float mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + sum+=Math.pow((aa[i]-mean), 4); + } + sum = sum/denom; + return sum/(Fmath.square(Stat.variance(aa))); + } + + public static float curtosis(float[] aa){ + return Stat.kurtosis(aa); + } + + // Kutosis excess of a 1D array of floats + public static float kurtosisExcess(float[] aa){ + return Stat.kurtosis(aa) - 3.0F; + } + + public static float curtosisExcess(float[] aa){ + return Stat.kurtosisExcess(aa); + } + + public static float excessKurtosis(float[] aa){ + return Stat.kurtosisExcess(aa); + } + + public static float excessCurtosis(float[] aa){ + return Stat.kurtosisExcess(aa); + } + + // Kutosis of a 1D array of BigInteger + public static BigDecimal kurtosis(BigInteger[] aa){ + ArrayMaths am = new ArrayMaths(aa); + BigDecimal[] bd = am.array_as_BigDecimal(); + return Stat.kurtosis(bd); + } + + public static BigDecimal curtosis(BigInteger[] aa){ + return Stat.kurtosis(aa); + } + + // Kutosis excess of a 1D array of BigInteger + public static BigDecimal kurtosisExcess(BigInteger[] aa){ + return Stat.kurtosis(aa).subtract(new BigDecimal("3.0")); + } + + public static BigDecimal curtosisExcess(BigInteger[] aa){ + return Stat.kurtosisExcess(aa); + } + + public static BigDecimal excessKurtosis(BigInteger[] aa){ + return Stat.kurtosisExcess(aa); + } + + public static BigDecimal excessCurtosis(BigInteger[] aa){ + return Stat.kurtosisExcess(aa); + } + + + // Kutosis of a 1D array of BigDecimal + public static BigDecimal kurtosis(BigDecimal[] aa){ + int n = aa.length; + double denom = (double)(n-1); + if(Stat.nFactorOptionS)denom = (double)n; + BigDecimal sum = BigDecimal.ZERO; + BigDecimal mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + BigDecimal hold = aa[i].subtract(mean); + sum = sum.add(hold.multiply(hold.multiply(hold.multiply(hold)))); + } + sum = sum.divide(new BigDecimal(denom), BigDecimal.ROUND_HALF_UP); + mean = Stat.variance(aa); + sum = sum.divide(mean.multiply(mean), BigDecimal.ROUND_HALF_UP); + mean = null; + return sum; + } + + public static BigDecimal curtosis(BigDecimal[] aa){ + return Stat.kurtosis(aa); + } + + // Kutosis excess of a 1D array of BigDecimal + public static BigDecimal kurtosisExcess(BigDecimal[] aa){ + return Stat.kurtosis(aa).subtract(new BigDecimal("3.0")); + } + + public static BigDecimal curtosisExcess(BigDecimal[] aa){ + return Stat.kurtosisExcess(aa); + } + + public static BigDecimal excessCurtosis(BigDecimal[] aa){ + return Stat.kurtosisExcess(aa); + } + + public static BigDecimal excessKurtosis(BigDecimal[] aa){ + return Stat.kurtosisExcess(aa); + } + + + // Kutosis of a 1D array of long + public static double kurtosis(long[] aa){ + int n = aa.length; + double denom = (double)(n-1); + if(Stat.nFactorOptionS)denom = (double)n; + double sum=0.0D; + double mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + sum+=Math.pow(((double)aa[i]-mean), 4); + } + sum = sum/denom; + return sum/Fmath.square(Stat.variance(aa)); + } + + public static double curtosis(long[] aa){ + return Stat.kurtosis(aa); + } + + // Kutosis excess of a 1D array of long + public static double kurtosisExcess(long[] aa){ + return Stat.kurtosis(aa) - 3.0D; + } + + public static double curtosisExcess(long[] aa){ + return Stat.kurtosisExcess(aa); + } + + public static double excessCurtosis(long[] aa){ + return Stat.kurtosisExcess(aa); + } + + public static double excessKurtosis(long[] aa){ + return Stat.kurtosisExcess(aa); + } + + + // Kutosis of a 1D array of int + public static double kurtosis(int[] aa){ + int n = aa.length; + double denom = (double)(n-1); + if(Stat.nFactorOptionS)denom = (double)n; + double sum=0.0D; + double mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + sum+=Math.pow((aa[i]-mean), 4); + } + sum = sum/denom; + return sum/Fmath.square(Stat.variance(aa)); + } + + public static double curtosis(int[] aa){ + return Stat.kurtosis(aa); + } + + // Kutosis excess of a 1D array of int + public static double kurtosisExcess(int[] aa){ + return Stat.kurtosis(aa) - 3.0D; + } + + public static double curtosisExcess(int[] aa){ + return Stat.kurtosisExcess(aa); + } + + public static double excessCurtosis(int[] aa){ + return Stat.kurtosisExcess(aa); + } + + public static double excessKurtosis(int[] aa){ + return Stat.kurtosisExcess(aa); + } + + // VARIANCE + // Static methods + // Variance of a 1D array of BigDecimals, aa + public static BigDecimal variance(BigDecimal[] aa){ + int n = aa.length; + BigDecimal sum = BigDecimal.ZERO; + BigDecimal mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + BigDecimal hold = aa[i].subtract(mean); + sum = sum.add(hold.multiply(hold)); + } + BigDecimal ret = sum.divide(new BigDecimal((double)(n-1)), BigDecimal.ROUND_HALF_UP); + if(Stat.nFactorOptionS) ret = sum.divide(new BigDecimal((double)n), BigDecimal.ROUND_HALF_UP); + sum = null; + mean = null; + return ret; } + + + // Variance of a 1D array of BigIntegers, aa + public static BigDecimal variance(BigInteger[] aa){ + int n = aa.length; + BigDecimal sum = BigDecimal.ZERO; + BigDecimal mean = BigDecimal.ZERO; + for(int i=0; i<n; i++){ + sum = sum.add(new BigDecimal(aa[i])); + } + mean = sum.divide(new BigDecimal((double)n), BigDecimal.ROUND_HALF_UP); + sum = BigDecimal.ZERO; + for(int i=0; i<n; i++){ + BigDecimal hold = new BigDecimal(aa[i]).subtract(mean); + sum = sum.add(hold.multiply(hold)); + } + BigDecimal ret = sum.divide(new BigDecimal((double)(n-1)), BigDecimal.ROUND_HALF_UP); + if(Stat.nFactorOptionS) ret = sum.divide(new BigDecimal((double)n), BigDecimal.ROUND_HALF_UP); + sum = null; + mean = null; + return ret; + } + + // Variance of a 1D array of Complex, aa + public static Complex variance(Complex[] aa){ + int n = aa.length; + Complex sum = Complex.zero(); + Complex mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + Complex hold = new Complex(aa[i]).minus(mean); + sum = sum.plus(hold.times(hold)); + } + Complex ret = sum.over(new Complex((double)(n-1))); + if(Stat.nFactorOptionS) ret = sum.over(new Complex((double)n)); + return ret; + } + + // Variance of a 1D array of Complex, aa, using conjugate formula + public static double varianceConjugateCalcn(Complex[] aa){ + int n = aa.length; + Complex sum = Complex.zero(); + Complex mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + Complex hold = new Complex(aa[i]).minus(mean); + sum = sum.plus(hold.times(hold.conjugate())); + } + double ret = sum.getReal()/(double)(n-1); + if(Stat.nFactorOptionS) ret = sum.getReal()/(double)n; + return ret; + } + + + // Variance of the moduli of a 1D array of Complex aa + public static double varianceModuli(Complex[] aa){ + ArrayMaths am = new ArrayMaths(aa); + double[] rl = am.array_as_modulus_of_Complex(); + double variance = Stat.variance(rl); + return variance; + } + + // Variance of the real parts of a 1D array of Complex aa + public static double varianceRealParts(Complex[] aa){ + ArrayMaths am = new ArrayMaths(aa); + double[] rl = am.array_as_real_part_of_Complex(); + double variance = Stat.variance(rl); + return variance; + } + + // Variance of the imaginary parts of a 1D array of Complex aa + public static double varianceImaginaryParts(Complex[] aa){ + ArrayMaths am = new ArrayMaths(aa); + double[] im = am.array_as_imaginary_part_of_Complex(); + double variance = Stat.variance(im); + return variance; + } + + // Variance of a 1D array of doubles, aa + public static double variance(double[] aa){ + int n = aa.length; + double sum=0.0D; + double mean = Stat.mean(aa); + sum=0.0D; + for(int i=0; i<n; i++){ + sum+=Fmath.square(aa[i]-mean); + } + double ret = sum/((double)(n-1)); + if(Stat.nFactorOptionS) ret = sum/((double)n); + return ret; + } + + // Variance of a 1D array of floats, aa + public static float variance(float[] aa){ + int n = aa.length; + float sum=0.0F; + float mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + sum+=Fmath.square(aa[i]-mean); + } + float ret = sum/((float)(n-1)); + if(Stat.nFactorOptionS) ret = sum/((float)n); + return ret; + } + + // Variance of a 1D array of int, aa + public static double variance(int[] aa){ + int n = aa.length; + double sum=0.0D; + double mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + sum+=Fmath.square((double)aa[i]-mean); + } + double ret = sum/((double)(n-1)); + if(Stat.nFactorOptionS) ret = sum/((double)n); + return ret; + } + + // Variance of a 1D array of long, aa + public static double variance(long[] aa){ + int n = aa.length; + double sum=0.0D; + double mean = Stat.mean(aa); + for(int i=0; i<n; i++){ + sum+=Fmath.square((double)aa[i]-mean); + } + double ret = sum/((double)(n-1)); + if(Stat.nFactorOptionS) ret = sum/((double)n); + return ret; + } + + // Weighted variance of a 1D array of doubles, aa + public static double variance(double[] aa, double[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + double nn = Stat.effectiveSampleNumber(ww); + double nterm = nn/(nn - 1.0); + if(Stat.nFactorOptionS)nterm = 1.0; + + double sumx=0.0D, sumw=0.0D, mean=0.0D; + double[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumx+=aa[i]*weight[i]; + sumw+=weight[i]; + } + mean=sumx/sumw; + sumx=0.0D; + for(int i=0; i<n; i++){ + sumx+=weight[i]*Fmath.square(aa[i]-mean); + } + return sumx*nterm/sumw; + } + + // Weighted variance of a 1D array of floats, aa + public static float variance(float[] aa, float[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + float nn = Stat.effectiveSampleNumber(ww); + float nterm = nn/(nn - 1.0F); + if(Stat.nFactorOptionS)nterm = 1.0F; + + float sumx=0.0F, sumw=0.0F, mean=0.0F; + float[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumx+=aa[i]*weight[i]; + sumw+=weight[i]; + } + mean=sumx/sumw; + sumx=0.0F; + for(int i=0; i<n; i++){ + sumx+=weight[i]*Fmath.square(aa[i]-mean); + } + return sumx*nterm/sumw; + } + + // Weighted variance of a 1D array of Complex aa + public static Complex variance(Complex[] aa, Complex[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + Complex nn = Stat.effectiveSampleNumber(ww); + Complex nterm = nn.over(nn.minus(1.0)); + if(Stat.nFactorOptionS)nterm = Complex.plusOne(); + Complex sumx=Complex.zero(); + Complex sumw=Complex.zero(); + Complex mean=Complex.zero(); + Complex[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumx = sumx.plus(aa[i].times(weight[i])); + sumw = sumw.plus(weight[i]); + } + mean=sumx.over(sumw); + sumx=Complex.zero(); + for(int i=0; i<n; i++){ + Complex hold = aa[i].minus(mean); + sumx = sumx.plus(weight[i].times(hold).times(hold)); + } + return (sumx.times(nterm)).over(sumw); + } + + // Weighted variance of a 1D array of Complex aa, using conjugate formula + public static double varianceConjugateCalcn(Complex[] aa, Complex[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + double nn = Stat.effectiveSampleNumberConjugateCalcn(ww); + double nterm = nn/(nn-1.0); + if(Stat.nFactorOptionS)nterm = 1.0; + Complex sumx=Complex.zero(); + Complex sumw=Complex.zero(); + Complex sumwc=Complex.zero(); + Complex mean=Complex.zero(); + Stat st = new Stat(ww); + st = st.invert(); + Complex[] weight = st.array_as_Complex(); + for(int i=0; i<n; i++){ + sumx = sumx.plus(aa[i].times(weight[i].times(weight[i]))); + sumw = sumw.plus(weight[i].times(weight[i])); + sumwc = sumwc.plus(weight[i].times(weight[i].conjugate())); + } + mean=sumx.over(sumw); + sumx=Complex.zero(); + + for(int i=0; i<n; i++){ + Complex hold = aa[i].minus(mean); + sumx = sumx.plus((weight[i].times(weight[i].conjugate())).times(hold).times(hold.conjugate())); + } + return nterm*((sumx.times(nterm)).over(sumwc)).getReal(); + } + + // Weighted variance of the moduli of a 1D array of Complex aa + public static double varianceModuli(Complex[] aa, Complex[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + ArrayMaths am = new ArrayMaths(aa); + double[] rl = am.array_as_modulus_of_Complex(); + ArrayMaths wm = new ArrayMaths(ww); + double[] wt = wm.array_as_modulus_of_Complex(); + double variance = Stat.variance(rl, wt); + return variance; + } + + // Weighted variance of the real parts of a 1D array of Complex aa + public static double varianceRealParts(Complex[] aa, Complex[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + ArrayMaths am = new ArrayMaths(aa); + double[] rl = am.array_as_real_part_of_Complex(); + ArrayMaths wm = new ArrayMaths(ww); + double[] wt = wm.array_as_real_part_of_Complex(); + double variance = Stat.variance(rl, wt); + return variance; + } + + // Weighted variance of the imaginary parts of a 1D array of Complex aa + public static double varianceImaginaryParts(Complex[] aa, Complex[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + ArrayMaths am = new ArrayMaths(aa); + double[] im = am.array_as_imaginary_part_of_Complex(); + ArrayMaths wm = new ArrayMaths(ww); + double[] wt = wm.array_as_imaginary_part_of_Complex(); + double variance = Stat.variance(im, wt); + return variance; + } + + + public static BigDecimal variance(BigDecimal[] aa, BigDecimal[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + BigDecimal nn = Stat.effectiveSampleNumber(ww); + BigDecimal nterm = nn.divide(nn.subtract(BigDecimal.ONE), BigDecimal.ROUND_HALF_UP); + if(Stat.nFactorOptionS)nterm = BigDecimal.ONE; + BigDecimal sumx=BigDecimal.ZERO; + BigDecimal sumw=BigDecimal.ZERO; + BigDecimal mean=BigDecimal.ZERO; + BigDecimal[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumx = sumx.add(aa[i].multiply(weight[i])); + sumw = sumw.add(weight[i]); + } + mean=sumx.divide(sumw, BigDecimal.ROUND_HALF_UP); + sumx=BigDecimal.ZERO; + for(int i=0; i<n; i++){ + sumx = sumx.add(weight[i].multiply(aa[i].subtract(mean)).multiply(aa[i].subtract(mean))); + } + sumx = (sumx.multiply(nterm).divide(sumw, BigDecimal.ROUND_HALF_UP)); + sumw = null; + mean = null; + weight = null; + nn = null; + nterm = null; + return sumx; + } + + public static BigDecimal variance(BigInteger[] aa, BigInteger[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + ArrayMaths aab = new ArrayMaths(aa); + ArrayMaths wwb = new ArrayMaths(ww); + return variance(aab.array_as_BigDecimal(), wwb.array_as_BigDecimal()); + } + + + // STANDARD ERROR OF THE MEAN + + // Standard error of the mean of a 1D array of BigDecimals, aa + public static double standardError(BigDecimal[] aa){ + return Math.sqrt(Stat.variance(aa).doubleValue()/aa.length); + } + + // Standard error of the mean of a 1D array of BigIntegers, aa + public static double standardError(BigInteger[] aa){ + return Math.sqrt(Stat.variance(aa).doubleValue()/aa.length); + } + + // Standard error of the mean of a 1D array of Complex, aa + public static Complex standardError(Complex[] aa){ + return Complex.sqrt(Stat.variance(aa).over(aa.length)); + } + + // Standard error of the mean of a 1D array of Complex, aa, conjugate formula + public static double standardErrorConjugateCalcn(Complex[] aa){ + return Math.sqrt(Stat.varianceConjugateCalcn(aa)/aa.length); + } + + // Standard error of the moduli of a 1D array of Complex aa + public static double standardErrorModuli(Complex[] aa){ + ArrayMaths am = new ArrayMaths(aa); + double[] rl = am.array_as_modulus_of_Complex(); + return Stat.standardError(rl); + } + + // Standard error of the real parts of a 1D array of Complex aa + public static double standardErrorRealParts(Complex[] aa){ + ArrayMaths am = new ArrayMaths(aa); + double[] rl = am.array_as_real_part_of_Complex(); + return Stat.standardError(rl); + } + + // Standard error of the imaginary parts of a 1D array of Complex aa + public static double standardErrorImaginaryParts(Complex[] aa){ + ArrayMaths am = new ArrayMaths(aa); + double[] im = am.array_as_imaginary_part_of_Complex(); + return Stat.standardError(im); + } + + // Standard error of the mean of a 1D array of doubles, aa + public static double standardError(double[] aa){ + return Math.sqrt(Stat.variance(aa)/aa.length); + } + + // Standard error of the mean of a 1D array of floats, aa + public static float standardError(float[] aa){ + return (float)Math.sqrt(Stat.variance(aa)/aa.length); + } + + // Standard error of the mean of a 1D array of int, aa + public static double standardError(int[] aa){ + return Math.sqrt(Stat.variance(aa)/aa.length); + } + + // Standard error of the mean of a 1D array of long, aa + public static double standardError(long[] aa){ + return Math.sqrt(Stat.variance(aa)/aa.length); + } + + // Standard error of the weighted mean of a 1D array of Complex, aa + public static Complex standardError(Complex[] aa, Complex[] ww){ + if(aa.length!=ww.length)throw new IllegalArgumentException("length of variable array, " + aa.length + " and length of weight array, " + ww.length + " are different"); + Complex effectiveNumber = Stat.effectiveSampleNumber(ww); + return Complex.sqrt((Stat.variance(aa, ww)).over(effectiveNumber)); + } + + // Standard error of the weighted mean of a 1D array of Complex, aa, using conjugate calculation + public static double standardErrorConjugateCalcn(Complex[] aa, Complex[] ww){ + if(aa.length!=ww.length)throw new IllegalArgumentException("length of variable array, " + aa.length + " and length of weight array, " + ww.length + " are different"); + double effectiveNumber = Stat.effectiveSampleNumberConjugateCalcn(ww); + return Math.sqrt(Stat.varianceConjugateCalcn(aa, ww)/effectiveNumber); + } + + // Weighted standard error of the moduli of a 1D array of Complex aa + public static double standardErrorModuli(Complex[] aa, Complex[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + ArrayMaths am = new ArrayMaths(aa); + double[] rl = am.array_as_modulus_of_Complex(); + ArrayMaths wm = new ArrayMaths(ww); + double[] wt = wm.array_as_modulus_of_Complex(); + return Stat.standardError(rl, wt); + } + + // Weighted standard error of the real parts of a 1D array of Complex aa + public static double standardErrorRealParts(Complex[] aa, Complex[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + ArrayMaths am = new ArrayMaths(aa); + double[] rl = am.array_as_real_part_of_Complex(); + ArrayMaths wm = new ArrayMaths(ww); + double[] wt = wm.array_as_real_part_of_Complex(); + return Stat.standardError(rl, wt); + } + + // Weighted standard error of the imaginary parts of a 1D array of Complex aa + public static double standardErrorImaginaryParts(Complex[] aa, Complex[] ww){ + int n = aa.length; + if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different"); + ArrayMaths am = new ArrayMaths(aa); + double[] im = am.array_as_imaginary_part_of_Complex(); + ArrayMaths wm = new ArrayMaths(ww); + double[] wt = wm.array_as_imaginary_part_of_Complex(); + return Stat.standardError(im, wt); + } + + + // Standard error of the weighted mean of a 1D array of BigDecimal, aa + public static double standardError(BigDecimal[] aa, BigDecimal[] ww){ + if(aa.length!=ww.length)throw new IllegalArgumentException("length of variable array, " + aa.length + " and length of weight array, " + ww.length + " are different"); + double effectiveNumber = (Stat.effectiveSampleNumber(ww)).doubleValue(); + return Math.sqrt(Stat.variance(aa, ww).doubleValue()/effectiveNumber); + } + + // Standard error of the weighted mean of a 1D array of BigInteger, aa + public static double standardError(BigInteger[] aa, BigInteger[] ww){ + if(aa.length!=ww.length)throw new IllegalArgumentException("length of variable array, " + aa.length + " and length of weight array, " + ww.length + " are different"); + double effectiveNumber = (Stat.effectiveSampleNumber(ww)).doubleValue(); + return Math.sqrt(Stat.variance(aa, ww).doubleValue()/effectiveNumber); + } + + // Standard error of the weighted mean of a 1D array of doubles, aa + public static double standardError(double[] aa, double[] ww){ + if(aa.length!=ww.length)throw new IllegalArgumentException("length of variable array, " + aa.length + " and length of weight array, " + ww.length + " are different"); + double effectiveNumber = Stat.effectiveSampleNumber(ww); + return Math.sqrt(Stat.variance(aa, ww)/effectiveNumber); + } + + // Standard error of the weighted mean of a 1D array of floats, aa + public static float standardError(float[] aa, float[] ww){ + float effectiveNumber = Stat.effectiveSampleNumber(ww); + return (float)Math.sqrt(Stat.variance(aa, ww)/effectiveNumber); + } + + // COVARIANCE + + // Covariance of two 1D arrays of doubles, xx and yy + public static double covariance(double[] xx, double[] yy){ + int n = xx.length; + if(n!=yy.length)throw new IllegalArgumentException("length of x variable array, " + n + " and length of y array, " + yy.length + " are different"); + double denom = (double)(n-1); + if(Stat.nFactorOptionS)denom = (double)n; + + double sumx=0.0D, meanx=0.0D; + double sumy=0.0D, meany=0.0D; + for(int i=0; i<n; i++){ + sumx+=xx[i]; + sumy+=yy[i]; + } + meanx=sumx/((double)n); + meany=sumy/((double)n); + double sum=0.0D; + for(int i=0; i<n; i++){ + sum+=(xx[i]-meanx)*(yy[i]-meany); + } + return sum/(denom); + } + + // Covariance of two 1D arrays of floats, xx and yy + public static float covariance(float[] xx, float[] yy){ + int n = xx.length; + if(n!=yy.length)throw new IllegalArgumentException("length of x variable array, " + n + " and length of y array, " + yy.length + " are different"); + float denom = (float)(n-1); + if(Stat.nFactorOptionS)denom = (float)n; + + float sumx=0.0F, meanx=0.0F; + float sumy=0.0F, meany=0.0F; + for(int i=0; i<n; i++){ + sumx+=xx[i]; + sumy+=yy[i]; + } + meanx=sumx/((float)n); + meany=sumy/((float)n); + float sum=0.0F; + for(int i=0; i<n; i++){ + sum+=(xx[i]-meanx)*(yy[i]-meany); + } + return sum/(denom); + } + + // Covariance of two 1D arrays of ints, xx and yy + public static double covariance(int[] xx, int[] yy){ + int n = xx.length; + if(n!=yy.length)throw new IllegalArgumentException("length of x variable array, " + n + " and length of y array, " + yy.length + " are different"); + double denom = (double)(n-1); + if(Stat.nFactorOptionS)denom = (double)n; + + double sumx=0.0D, meanx=0.0D; + double sumy=0.0D, meany=0.0D; + for(int i=0; i<n; i++){ + sumx+=(double)xx[i]; + sumy+=(double)yy[i]; + } + meanx=sumx/((double)n); + meany=sumy/((double)n); + double sum=0.0D; + for(int i=0; i<n; i++){ + sum+=((double)xx[i]-meanx)*((double)yy[i]-meany); + } + return sum/(denom); + } + + // Covariance of two 1D arrays of ints, xx and yy + public static double covariance(long[] xx, long[] yy){ + int n = xx.length; + if(n!=yy.length)throw new IllegalArgumentException("length of x variable array, " + n + " and length of y array, " + yy.length + " are different"); + double denom = (double)(n-1); + if(Stat.nFactorOptionS)denom = (double)n; + + double sumx=0.0D, meanx=0.0D; + double sumy=0.0D, meany=0.0D; + for(int i=0; i<n; i++){ + sumx+=(double)xx[i]; + sumy+=(double)yy[i]; + } + meanx=sumx/((double)n); + meany=sumy/((double)n); + double sum=0.0D; + for(int i=0; i<n; i++){ + sum+=((double)xx[i]-meanx)*((double)yy[i]-meany); + } + return sum/(denom); + } + + // Weighted covariance of two 1D arrays of doubles, xx and yy with weights ww + public static double covariance(double[] xx, double[] yy, double[] ww){ + int n = xx.length; + if(n!=yy.length)throw new IllegalArgumentException("length of x variable array, " + n + " and length of y array, " + yy.length + " are different"); + if(n!=ww.length)throw new IllegalArgumentException("length of x variable array, " + n + " and length of weight array, " + yy.length + " are different"); + double nn = Stat.effectiveSampleNumber(ww); + double nterm = nn/(nn - 1.0); + if(Stat.nFactorOptionS)nterm = 1.0; + double sumx=0.0D, sumy=0.0D, sumw=0.0D, meanx=0.0D, meany=0.0D; + double[] weight = Stat.invertAndSquare(ww); + for(int i=0; i<n; i++){ + sumx+=xx[i]*weight[i]; + sumy+=yy[i]*weight[i]; + sumw+=weight[i]; + } + meanx=sumx/sumw; + meany=sumy/sumw; + + double sum=0.0D; + for(int i=0; i<n; i++){ + sum+=weight[i]*(xx[i]-meanx)*(yy[i]-meany); + } + return sum*nterm/sumw; + } + + + // CORRELATION COEFFICIENT + + // Calculate correlation coefficient + // x y data as double + public static double corrCoeff(double[] xx, double[]yy){ + + double temp0 = 0.0D, temp1 = 0.0D; // working variables + int nData = xx.length; + if(yy.length!=nData)throw new IllegalArgumentException("array lengths must be equal"); + int df = nData-1; + // means + double mx = 0.0D; + double my = 0.0D; + for(int i=0; i<nData; i++){ + mx += xx[i]; + my += yy[i]; + } + mx /= nData; + my /= nData; + + // calculate sample variances + double s2xx = 0.0D; + double s2yy = 0.0D; + double s2xy = 0.0D; + for(int i=0; i<nData; i++){ + s2xx += Fmath.square(xx[i]-mx); + s2yy += Fmath.square(yy[i]-my); + s2xy += (xx[i]-mx)*(yy[i]-my); + } + + // calculate corelation coefficient + double sampleR = s2xy/Math.sqrt(s2xx*s2yy); + + return sampleR; + } + + // Calculate correlation coefficient + // x y data as float + public static float corrCoeff(float[] x, float[] y){ + int nData = x.length; + if(y.length!=nData)throw new IllegalArgumentException("array lengths must be equal"); + int n = x.length; + double[] xx = new double[n]; + double[] yy = new double[n]; + for(int i=0; i<n; i++){ + xx[i] = (double)x[i]; + yy[i] = (double)y[i]; + } + return (float)Stat.corrCoeff(xx, yy); + } + + // Calculate correlation coefficient + // x y data as int + public static double corrCoeff(int[] x, int[]y){ + int n = x.length; + if(y.length!=n)throw new IllegalArgumentException("array lengths must be equal"); + + double[] xx = new double[n]; + double[] yy = new double[n]; + for(int i=0; i<n; i++){ + xx[i] = (double)x[i]; + yy[i] = (double)y[i]; + } + return Stat.corrCoeff(xx, yy); + } + + // Calculate weighted correlation coefficient + // x y data and weights w as double + public static double corrCoeff(double[] x, double[]y, double[] w){ + int n = x.length; + if(y.length!=n)throw new IllegalArgumentException("x and y array lengths must be equal"); + if(w.length!=n)throw new IllegalArgumentException("x and weight array lengths must be equal"); + + double sxy = Stat.covariance(x, y, w); + double sx = Stat.variance(x, w); + double sy = Stat.variance(y, w); + return sxy/Math.sqrt(sx*sy); + } + + // Calculate correlation coefficient + // Binary data x and y + // Input is the frequency matrix, F, elements, f(i,j) + // f(0,0) - element00 - frequency of x and y both = 1 + // f(0,1) - element01 - frequency of x = 0 and y = 1 + // f(1,0) - element10 - frequency of x = 1 and y = 0 + // f(1,1) - element11 - frequency of x and y both = 0 + public static double corrCoeff(int element00, int element01, int element10, int element11){ + return ((double)(element00*element11 - element01*element10))/Math.sqrt((double)((element00+element01)*(element10+element11)*(element00+element10)*(element01+element11))); + } + + // Calculate correlation coefficient + // Binary data x and y + // Input is the frequency matrix, F + // F(0,0) - frequency of x and y both = 1 + // F(0,1) - frequency of x = 0 and y = 1 + // F(1,0) - frequency of x = 1 and y = 0 + // F(1,1) - frequency of x and y both = 0 + public static double corrCoeff(int[][] freqMatrix){ + double element00 = (double)freqMatrix[0][0]; + double element01 = (double)freqMatrix[0][1]; + double element10 = (double)freqMatrix[1][0]; + double element11 = (double)freqMatrix[1][1]; + return ((element00*element11 - element01*element10))/Math.sqrt(((element00+element01)*(element10+element11)*(element00+element10)*(element01+element11))); + } + + // Linear correlation coefficient cumulative probablity + // old name calls renamed method + public static double linearCorrCoeffProb(double rCoeff, int nu){ + return corrCoeffProb(rCoeff, nu); + } + + // Linear correlation coefficient cumulative probablity + public static double corrCoeffProb(double rCoeff, int nu){ + if(Math.abs(rCoeff)>1.0D)throw new IllegalArgumentException("|Correlation coefficient| > 1 : " + rCoeff); + + // Create instances of the classes holding the function evaluation methods + CorrCoeff cc = new CorrCoeff(); + + // Assign values to constant in the function + cc.a = ((double)nu - 2.0D)/2.0D; + + + double integral = Integration.gaussQuad(cc, Math.abs(rCoeff), 1.0D, 128); + + double preterm = Math.exp(Stat.logGamma((nu+1.0D)/2.0)-Stat.logGamma(nu/2.0D))/Math.sqrt(Math.PI); + + return preterm*integral; + } + + // Linear correlation coefficient single probablity + // old name calls renamed method + public static double linearCorrCoeff(double rCoeff, int nu){ + return Stat.corrCoeffPDF(rCoeff, nu); + } + + // Linear correlation coefficient single probablity + public static double corrCoeffPDF(double rCoeff, int nu){ + if(Math.abs(rCoeff)>1.0D)throw new IllegalArgumentException("|Correlation coefficient| > 1 : " + rCoeff); + + double a = ((double)nu - 2.0D)/2.0D; + double y = Math.pow((1.0D - Fmath.square(rCoeff)),a); + + double preterm = Math.exp(Stat.logGamma((nu+1.0D)/2.0)-Stat.logGamma(nu/2.0D))/Math.sqrt(Math.PI); + + return preterm*y; + } + + // Linear correlation coefficient single probablity + public static double corrCoeffPdf(double rCoeff, int nu){ + if(Math.abs(rCoeff)>1.0D)throw new IllegalArgumentException("|Correlation coefficient| > 1 : " + rCoeff); + + double a = ((double)nu - 2.0D)/2.0D; + double y = Math.pow((1.0D - Fmath.square(rCoeff)),a); + + double preterm = Math.exp(Stat.logGamma((nu+1.0D)/2.0)-Stat.logGamma(nu/2.0D))/Math.sqrt(Math.PI); + + return preterm*y; + } + + // SHANNON ENTROPY (STATIC METHODS) + // Shannon Entropy returned as bits + public static double shannonEntropy(double[] p){ + ArrayMaths am = new ArrayMaths(p); + double max = am.getMaximum_as_double(); + if(max>1.0)throw new IllegalArgumentException("All probabilites must be less than or equal to 1; the maximum supplied probabilty is " + max); + double min = am.getMinimum_as_double(); + if(min<0.0)throw new IllegalArgumentException("All probabilites must be greater than or equal to 0; the minimum supplied probabilty is " + min); + double total = am.getSum_as_double(); + if(!Fmath.isEqualWithinPerCent(total, 1.0D, 0.1D))throw new IllegalArgumentException("the probabilites must add up to 1 within an error of 0.1%; they add up to " + total); + + return am.minusxLog2x().getSum_as_double(); + } + + // Shannon Entropy returned as bits + public static double shannonEntropyBit(double[] p){ + return shannonEntropy(p); + } + + // Shannon Entropy returned as nats (nits) + public static double shannonEntropyNat(double[] p){ + ArrayMaths am = new ArrayMaths(p); + double max = am.getMaximum_as_double(); + if(max>1.0)throw new IllegalArgumentException("All probabilites must be less than or equal to 1; the maximum supplied probabilty is " + max); + double min = am.getMinimum_as_double(); + if(min<0.0)throw new IllegalArgumentException("All probabilites must be greater than or equal to 0; the minimum supplied probabilty is " + min); + double total = am.getSum_as_double(); + if(!Fmath.isEqualWithinPerCent(total, 1.0D, 0.1D))throw new IllegalArgumentException("the probabilites must add up to 1 within an error of 0.1%; they add up to " + total); + + return am.minusxLogEx().getSum_as_double(); + } + + // Shannon Entropy returned as dits + public static double shannonEntropyDit(double[] p){ + ArrayMaths am = new ArrayMaths(p); + double max = am.getMaximum_as_double(); + if(max>1.0)throw new IllegalArgumentException("All probabilites must be less than or equal to 1; the maximum supplied probabilty is " + max); + double min = am.getMinimum_as_double(); + if(min<0.0)throw new IllegalArgumentException("All probabilites must be greater than or equal to 0; the minimum supplied probabilty is " + min); + double total = am.getSum_as_double(); + if(!Fmath.isEqualWithinPerCent(total, 1.0D, 0.1D))throw new IllegalArgumentException("the probabilites must add up to 1 within an error of 0.1%; they add up to " + total); + + return am.minusxLog10x().getSum_as_double(); + } + + // Binary Shannon Entropy returned as bits + public static double binaryShannonEntropy(double p){ + if(p>1.0)throw new IllegalArgumentException("The probabiliy, " + p + ", must be less than or equal to 1"); + if(p<0.0)throw new IllegalArgumentException("The probabiliy, " + p + ", must be greater than or equal to 0"); + double entropy = 0.0D; + if(p>0.0D && p<1.0D){ + entropy = -p*Fmath.log2(p) - (1-p)*Fmath.log2(1-p); + } + return entropy; + } + + // Binary Shannon Entropy returned as bits + public static double binaryShannonEntropyBit(double p){ + return binaryShannonEntropy(p); + } + + // Binary Shannon Entropy returned as nats (nits) + public static double binaryShannonEntropyNat(double p){ + if(p>1.0)throw new IllegalArgumentException("The probabiliy, " + p + ", must be less than or equal to 1"); + if(p<0.0)throw new IllegalArgumentException("The probabiliy, " + p + ", must be greater than or equal to 0"); + double entropy = 0.0D; + if(p>0.0D && p<1.0D){ + entropy = -p*Math.log(p) - (1-p)*Math.log(1-p); + } + return entropy; + } + + // Binary Shannon Entropy returned as dits + public static double binaryShannonEntropyDit(double p){ + if(p>1.0)throw new IllegalArgumentException("The probabiliy, " + p + ", must be less than or equal to 1"); + if(p<0.0)throw new IllegalArgumentException("The probabiliy, " + p + ", must be greater than or equal to 0"); + double entropy = 0.0D; + if(p>0.0D && p<1.0D){ + entropy = -p*Math.log10(p) - (1-p)*Math.log10(1-p); + } + return entropy; + + } + + // RENYI ENTROPY + // Renyi Entropy returned as bits + public static double renyiEntropy(double[] p, double alpha){ + ArrayMaths am = new ArrayMaths(p); + double max = am.getMaximum_as_double(); + if(max>1.0)throw new IllegalArgumentException("All probabilites must be less than or equal to 1; the maximum supplied probabilty is " + max); + double min = am.getMinimum_as_double(); + if(min<0.0)throw new IllegalArgumentException("All probabilites must be greater than or equal to 0; the minimum supplied probabilty is " + min); + double total = am.getSum_as_double(); + if(!Fmath.isEqualWithinPerCent(total, 1.0D, 0.1D))throw new IllegalArgumentException("the probabilites must add up to 1 within an error of 0.1%; they add up to " + total); + if(alpha<0.0D)throw new IllegalArgumentException("alpha, " + alpha + ", must be greater than or equal to 0"); + double entropy = 0.0; + if(alpha==0.0D){ + entropy = Fmath.log2(p.length); + } + else{ + if(alpha==1.0D){ + entropy = Stat.shannonEntropy(p); + } + else{ + if(Fmath.isPlusInfinity(alpha)){ + entropy = -Fmath.log2(max); + } + else{ + if(alpha<=3000){ + am = am.pow(alpha); + boolean testUnderFlow = false; + if(am.getMaximum_as_double()==Double.MIN_VALUE)testUnderFlow = true; + entropy = Fmath.log2(am.getSum_as_double())/(1.0D - alpha); + if(Fmath.isPlusInfinity(entropy) || testUnderFlow){ + entropy = -Fmath.log2(max); + double entropyMin = entropy; + System.out.println("Stat: renyiEntropy/renyiEntopyBit: underflow or overflow in calculating the entropy"); + boolean test1 = true; + boolean test2 = true; + boolean test3 = true; + int iter = 0; + double alpha2 = alpha/2.0; + double entropy2 = 0.0; + while(test3){ + while(test1){ + ArrayMaths am2 = new ArrayMaths(p); + am2 = am2.pow(alpha2); + entropy2 = Fmath.log2(am2.getSum_as_double())/(1.0D - alpha2); + if(Fmath.isPlusInfinity(entropy2)){ + alpha2 /= 2.0D; + iter++; + if(iter==100000){ + test1=false; + test2=false; + } + } + else{ + test1 = false; + } + } + double alphaTest = alpha2 + 40.0D*alpha/1000.0D; + ArrayMaths am3 = new ArrayMaths(p); + am3 = am3.pow(alphaTest); + double entropy3 = Fmath.log2(am3.getSum_as_double())/(1.0D - alphaTest); + if(!Fmath.isPlusInfinity(entropy3)){ + test3=false; + } + else{ + alpha2 /= 2.0D; + } + } + double entropyLast = entropy2; + double alphaLast = alpha2; + ArrayList<Double> extrap = new ArrayList<Double>(); + if(test2){ + double diff = alpha2/1000.0D; + test1 = true; + while(test1){ + extrap.add(new Double(alpha2)); + extrap.add(new Double(entropy2)); + entropyLast = entropy2; + alphaLast = alpha2; + alpha2 += diff; + ArrayMaths am2 = new ArrayMaths(p); + am2 = am2.pow(alpha2); + entropy2 = Fmath.log2(am2.getSum_as_double())/(1.0D - alpha2); + if(Fmath.isPlusInfinity(entropy2)){ + test1 = false; + entropy2 = entropyLast; + alpha2 = alphaLast; + } + } + } + int nex = extrap.size()/2 - 20; + double[] alphaex= new double[nex]; + double[] entroex= new double[nex]; + int ii = -1; + for(int i=0; i<nex; i++){ + alphaex[i] = (extrap.get(++ii)).doubleValue(); + entroex[i] = Math.log((extrap.get(++ii)).doubleValue() - entropyMin); + } + Regression reg = new Regression(alphaex, entroex); + reg.linear(); + double[] param = reg.getCoeff(); + entropy = Math.exp(param[0] + param[1]*alpha) + entropyMin; + + + System.out.println("An interpolated entropy of " + entropy + " returned (see documentation for exponential interpolation)"); + System.out.println("Lowest calculable value = " + (Math.exp(entroex[nex-1])+entropyMin) + ", alpha = " + alphaex[nex-1]); + System.out.println("Minimum entropy value = " + entropyMin + ", alpha = infinity"); + } + } + else{ + entropy = -Fmath.log2(max); + System.out.println("Stat: renyiEntropy/renyiEntropyBit: underflow or overflow in calculating the entropy"); + System.out.println("An interpolated entropy of " + entropy + " returned (see documentation for exponential interpolation)"); + } + } + } + } + return entropy; + } + + // Renyi Entropy returned as nats + public static double renyiEntropyNat(double[] p, double alpha){ + ArrayMaths am = new ArrayMaths(p); + double max = am.getMaximum_as_double(); + if(max>1.0)throw new IllegalArgumentException("All probabilites must be less than or equal to 1; the maximum supplied probabilty is " + max); + double min = am.getMinimum_as_double(); + if(min<0.0)throw new IllegalArgumentException("All probabilites must be greater than or equal to 0; the minimum supplied probabilty is " + min); + double total = am.getSum_as_double(); + if(!Fmath.isEqualWithinPerCent(total, 1.0D, 0.1D))throw new IllegalArgumentException("the probabilites must add up to 1 within an error of 0.1%; they add up to " + total); + if(alpha<0.0D)throw new IllegalArgumentException("alpha, " + alpha + ", must be greater than or equal to 0"); + double entropy = 0.0; + if(alpha==0.0D){ + entropy = Math.log(p.length); + } + else{ + if(alpha==1.0D){ + entropy = Stat.shannonEntropy(p); + } + else{ + if(Fmath.isPlusInfinity(alpha)){ + entropy = -Math.log(max); + } + else{ + if(alpha<=3000){ + am = am.pow(alpha); + boolean testUnderFlow = false; + if(am.getMaximum_as_double()==Double.MIN_VALUE)testUnderFlow = true; + entropy = Math.log(am.getSum_as_double())/(1.0D - alpha); + if(Fmath.isPlusInfinity(entropy) || testUnderFlow){ + entropy = -Math.log(max); + double entropyMin = entropy; + System.out.println("Stat: renyiEntropyNat: underflow or overflow in calculating the entropy"); + boolean test1 = true; + boolean test2 = true; + boolean test3 = true; + int iter = 0; + double alpha2 = alpha/2.0; + double entropy2 = 0.0; + while(test3){ + while(test1){ + ArrayMaths am2 = new ArrayMaths(p); + am2 = am2.pow(alpha2); + entropy2 = Math.log(am2.getSum_as_double())/(1.0D - alpha2); + if(Fmath.isPlusInfinity(entropy2)){ + alpha2 /= 2.0D; + iter++; + if(iter==100000){ + test1=false; + test2=false; + } + } + else{ + test1 = false; + } + } + double alphaTest = alpha2 + 40.0D*alpha/1000.0D; + ArrayMaths am3 = new ArrayMaths(p); + am3 = am3.pow(alphaTest); + double entropy3 = Math.log(am3.getSum_as_double())/(1.0D - alphaTest); + if(!Fmath.isPlusInfinity(entropy3)){ + test3=false; + } + else{ + alpha2 /= 2.0D; + } + } + double entropyLast = entropy2; + double alphaLast = alpha2; + ArrayList<Double> extrap = new ArrayList<Double>(); + if(test2){ + double diff = alpha2/1000.0D; + test1 = true; + while(test1){ + extrap.add(new Double(alpha2)); + extrap.add(new Double(entropy2)); + entropyLast = entropy2; + alphaLast = alpha2; + alpha2 += diff; + ArrayMaths am2 = new ArrayMaths(p); + am2 = am2.pow(alpha2); + entropy2 = Math.log(am2.getSum_as_double())/(1.0D - alpha2); + if(Fmath.isPlusInfinity(entropy2)){ + test1 = false; + entropy2 = entropyLast; + alpha2 = alphaLast; + } + } + } + int nex = extrap.size()/2 - 20; + double[] alphaex= new double[nex]; + double[] entroex= new double[nex]; + int ii = -1; + for(int i=0; i<nex; i++){ + alphaex[i] = (extrap.get(++ii)).doubleValue(); + entroex[i] = Math.log((extrap.get(++ii)).doubleValue() - entropyMin); + } + Regression reg = new Regression(alphaex, entroex); + reg.linear(); + double[] param = reg.getCoeff(); + entropy = Math.exp(param[0] + param[1]*alpha) + entropyMin; + + + System.out.println("An interpolated entropy of " + entropy + " returned (see documentation for exponential interpolation)"); + System.out.println("Lowest calculable value = " + (Math.exp(entroex[nex-1])+entropyMin) + ", alpha = " + alphaex[nex-1]); + System.out.println("Minimum entropy value = " + entropyMin + ", alpha = infinity"); + } + } + else{ + entropy = -Math.log(max); + System.out.println("Stat: renyiEntropyNat: underflow or overflow in calculating the entropy"); + System.out.println("An interpolated entropy of " + entropy + " returned (see documentation for exponential interpolation)"); + } + } + } + } + return entropy; + } + + // Renyi Entropy returned as dits + public static double renyiEntropyDit(double[] p, double alpha){ + ArrayMaths am = new ArrayMaths(p); + double max = am.getMaximum_as_double(); + if(max>1.0)throw new IllegalArgumentException("All probabilites must be less than or equal to 1; the maximum supplied probabilty is " + max); + double min = am.getMinimum_as_double(); + if(min<0.0)throw new IllegalArgumentException("All probabilites must be greater than or equal to 0; the minimum supplied probabilty is " + min); + double total = am.getSum_as_double(); + if(!Fmath.isEqualWithinPerCent(total, 1.0D, 0.1D))throw new IllegalArgumentException("the probabilites must add up to 1 within an error of 0.1%; they add up to " + total); + if(alpha<0.0D)throw new IllegalArgumentException("alpha, " + alpha + ", must be greater than or equal to 0"); + double entropy = 0.0; + if(alpha==0.0D){ + entropy = Math.log10(p.length); + } + else{ + if(alpha==1.0D){ + entropy = Stat.shannonEntropy(p); + } + else{ + if(Fmath.isPlusInfinity(alpha)){ + entropy = -Math.log10(max); + } + else{ + if(alpha<=3000){ + am = am.pow(alpha); + boolean testUnderFlow = false; + if(am.getMaximum_as_double()==Double.MIN_VALUE)testUnderFlow = true; + entropy = Math.log10(am.getSum_as_double())/(1.0D - alpha); + if(Fmath.isPlusInfinity(entropy) || testUnderFlow){ + entropy = -Math.log10(max); + double entropyMin = entropy; + System.out.println("Stat: renyiEntropyDit: underflow or overflow in calculating the entropy"); + boolean test1 = true; + boolean test2 = true; + boolean test3 = true; + int iter = 0; + double alpha2 = alpha/2.0; + double entropy2 = 0.0; + while(test3){ + while(test1){ + ArrayMaths am2 = new ArrayMaths(p); + am2 = am2.pow(alpha2); + entropy2 = Math.log10(am2.getSum_as_double())/(1.0D - alpha2); + if(Fmath.isPlusInfinity(entropy2)){ + alpha2 /= 2.0D; + iter++; + if(iter==100000){ + test1=false; + test2=false; + } + } + else{ + test1 = false; + } + } + double alphaTest = alpha2 + 40.0D*alpha/1000.0D; + ArrayMaths am3 = new ArrayMaths(p); + am3 = am3.pow(alphaTest); + double entropy3 = Math.log10(am3.getSum_as_double())/(1.0D - alphaTest); + if(!Fmath.isPlusInfinity(entropy3)){ + test3=false; + } + else{ + alpha2 /= 2.0D; + } + } + double entropyLast = entropy2; + double alphaLast = alpha2; + ArrayList<Double> extrap = new ArrayList<Double>(); + if(test2){ + double diff = alpha2/1000.0D; + test1 = true; + while(test1){ + extrap.add(new Double(alpha2)); + extrap.add(new Double(entropy2)); + entropyLast = entropy2; + alphaLast = alpha2; + alpha2 += diff; + ArrayMaths am2 = new ArrayMaths(p); + am2 = am2.pow(alpha2); + entropy2 = Math.log10(am2.getSum_as_double())/(1.0D - alpha2); + if(Fmath.isPlusInfinity(entropy2)){ + test1 = false; + entropy2 = entropyLast; + alpha2 = alphaLast; + } + } + } + int nex = extrap.size()/2 - 20; + double[] alphaex= new double[nex]; + double[] entroex= new double[nex]; + int ii = -1; + for(int i=0; i<nex; i++){ + alphaex[i] = (extrap.get(++ii)).doubleValue(); + entroex[i] = Math.log10((extrap.get(++ii)).doubleValue() - entropyMin); + } + Regression reg = new Regression(alphaex, entroex); + reg.linear(); + double[] param = reg.getCoeff(); + entropy = Math.exp(param[0] + param[1]*alpha) + entropyMin; + + + System.out.println("An interpolated entropy of " + entropy + " returned (see documentation for exponential interpolation)"); + System.out.println("Lowest calculable value = " + (Math.exp(entroex[nex-1])+entropyMin) + ", alpha = " + alphaex[nex-1]); + System.out.println("Minimum entropy value = " + entropyMin + ", alpha = infinity"); + } + } + else{ + entropy = -Math.log10(max); + System.out.println("Stat: renyiEntropyDit: underflow or overflow in calculating the entropy"); + System.out.println("An interpolated entropy of " + entropy + " returned (see documentation for exponential interpolation)"); + } + } + } + } + return entropy; + } + + + + // Renyi Entropy returned as bits + public static double renyiEntropyBit(double[] p, double alpha){ + return renyiEntropy(p, alpha); + } + + + // TSALLIS ENTROPY (STATIC METHODS) + // Tsallis Entropy + public static double tsallisEntropyNat(double[] p, double q){ + ArrayMaths am = new ArrayMaths(p); + double max = am.getMaximum_as_double(); + if(max>1.0D)throw new IllegalArgumentException("All probabilites must be less than or equal to 1; the maximum supplied probabilty is " + max); + double min = am.getMinimum_as_double(); + if(min<0.0D)throw new IllegalArgumentException("All probabilites must be greater than or equal to 0; the minimum supplied probabilty is " + min); + double total = am.getSum_as_double(); + if(!Fmath.isEqualWithinPerCent(total, 1.0D, 0.1D))throw new IllegalArgumentException("the probabilites must add up to 1 within an error of 0.1%; they add up to " + total); + + if(q==1.0D){ + return Stat.shannonEntropyNat(p); + } + else{ + am = am.pow(q); + return (1.0D - am.getSum_as_double())/(q - 1.0D); + + } + } + + // GENERALIZED ENTROPY (STATIC METHOD) + public static double generalizedEntropyOneNat(double[] p, double q, double r){ + ArrayMaths am = new ArrayMaths(p); + double max = am.getMaximum_as_double(); + if(max>1.0D)throw new IllegalArgumentException("All probabilites must be less than or equal to 1; the maximum supplied probabilty is " + max); + double min = am.getMinimum_as_double(); + if(min<0.0D)throw new IllegalArgumentException("All probabilites must be greater than or equal to 0; the minimum supplied probabilty is " + min); + double total = am.getSum_as_double(); + if(!Fmath.isEqualWithinPerCent(total, 1.0D, 0.1D))throw new IllegalArgumentException("the probabilites must add up to 1 within an error of 0.1%; they add up to " + total); + if(r==0.0D){ + return Stat.renyiEntropyNat(p, q); + } + else{ + if(r==1.0D){ + return Stat.tsallisEntropyNat(p, q); + } + else{ + if(q==1.0D){ + double[] tsen = new double[10]; + double[] tsqq = new double[10]; + double qq = 0.995; + for(int i=0; i<5; i++){ + ArrayMaths am1 = am.pow(qq); + tsen[i] = (1.0D - Math.pow(am1.getSum_as_double(), r))/(r*(qq - 1.0)); + tsqq[i] = qq; + qq += 0.001; + } + qq = 1.001; + for(int i=5; i<10; i++){ + ArrayMaths am1 = am.pow(qq); + tsen[i]= (1.0D - Math.pow(am1.getSum_as_double(), r))/(r*(qq - 1.0)); + tsqq[i] = qq; + qq += 0.001; + } + Regression reg = new Regression(tsqq, tsen); + reg.polynomial(2); + double[] param = reg.getCoeff(); + return param[0] + param[1] + param[2]; + } + else{ + am = am.pow(q); + return (1.0D - Math.pow(am.getSum_as_double(), r))/(r*(q - 1.0)); + } + } + } + } + + public static double generalisedEntropyOneNat(double[] p, double q, double r){ + return generalizedEntropyOneNat(p, q, r); + } + + + // HISTOGRAMS + + // Distribute data into bins to obtain histogram + // zero bin position and upper limit provided + public static double[][] histogramBins(double[] data, double binWidth, double binZero, double binUpper){ + int n = 0; // new array length + int m = data.length; // old array length; + for(int i=0; i<m; i++)if(data[i]<=binUpper)n++; + if(n!=m){ + double[] newData = new double[n]; + int j = 0; + for(int i=0; i<m; i++){ + if(data[i]<=binUpper){ + newData[j] = data[i]; + j++; + } + } + System.out.println((m-n)+" data points, above histogram upper limit, excluded in Stat.histogramBins"); + return histogramBins(newData, binWidth, binZero); + } + else{ + return histogramBins(data, binWidth, binZero); + + } + } + + // Distribute data into bins to obtain histogram + // zero bin position provided + public static double[][] histogramBins(double[] data, double binWidth, double binZero){ + double dmax = Fmath.maximum(data); + int nBins = (int) Math.ceil((dmax - binZero)/binWidth); + if(binZero+nBins*binWidth>dmax)nBins++; + int nPoints = data.length; + int[] dataCheck = new int[nPoints]; + for(int i=0; i<nPoints; i++)dataCheck[i]=0; + double[]binWall = new double[nBins+1]; + binWall[0]=binZero; + for(int i=1; i<=nBins; i++){ + binWall[i] = binWall[i-1] + binWidth; + } + double[][] binFreq = new double[2][nBins]; + for(int i=0; i<nBins; i++){ + binFreq[0][i]= (binWall[i]+binWall[i+1])/2.0D; + binFreq[1][i]= 0.0D; + } + boolean test = true; + + for(int i=0; i<nPoints; i++){ + test=true; + int j=0; + while(test){ + if(j==nBins-1){ + if(data[i]>=binWall[j] && data[i]<=binWall[j+1]*(1.0D + Stat.histTol)){ + binFreq[1][j]+= 1.0D; + dataCheck[i]=1; + test=false; + } + } + else{ + if(data[i]>=binWall[j] && data[i]<binWall[j+1]){ + binFreq[1][j]+= 1.0D; + dataCheck[i]=1; + test=false; + } + } + if(test){ + if(j==nBins-1){ + test=false; + } + else{ + j++; + } + } + } + } + int nMissed=0; + for(int i=0; i<nPoints; i++)if(dataCheck[i]==0){ + nMissed++; + System.out.println("p " + i + " " + data[i] + " " + binWall[0] + " " + binWall[nBins]); + } + if(nMissed>0)System.out.println(nMissed+" data points, outside histogram limits, excluded in Stat.histogramBins"); + return binFreq; + } + + // Distribute data into bins to obtain histogram + // zero bin position calculated + public static double[][] histogramBins(double[] data, double binWidth){ + + double dmin = Fmath.minimum(data); + double dmax = Fmath.maximum(data); + double span = dmax - dmin; + double binZero = dmin; + int nBins = (int) Math.ceil(span/binWidth); + double histoSpan = ((double)nBins)*binWidth; + double rem = histoSpan - span; + if(rem>=0){ + binZero -= rem/2.0D; + } + else{ + if(Math.abs(rem)/span>histTol){ + // readjust binWidth + boolean testBw = true; + double incr = histTol/nBins; + int iTest = 0; + while(testBw){ + binWidth += incr; + histoSpan = ((double)nBins)*binWidth; + rem = histoSpan - span; + if(rem<0){ + iTest++; + if(iTest>1000){ + testBw = false; + System.out.println("histogram method could not encompass all data within histogram\nContact Michael thomas Flanagan"); + } + } + else{ + testBw = false; + } + } + } + } + + return Stat.histogramBins(data, binWidth, binZero); + } + + // Distribute data into bins to obtain histogram and plot histogram + // zero bin position and upper limit provided + public static double[][] histogramBinsPlot(double[] data, double binWidth, double binZero, double binUpper){ + String xLegend = null; + return histogramBinsPlot(data, binWidth, binZero, binUpper, xLegend); + } + + // Distribute data into bins to obtain histogram and plot histogram + // zero bin position, upper limit and x-axis legend provided + public static double[][] histogramBinsPlot(double[] data, double binWidth, double binZero, double binUpper, String xLegend){ + int n = 0; // new array length + int m = data.length; // old array length; + for(int i=0; i<m; i++)if(data[i]<=binUpper)n++; + if(n!=m){ + double[] newData = new double[n]; + int j = 0; + for(int i=0; i<m; i++){ + if(data[i]<=binUpper){ + newData[j] = data[i]; + j++; + } + } + System.out.println((m-n)+" data points, above histogram upper limit, excluded in Stat.histogramBins"); + return histogramBinsPlot(newData, binWidth, binZero, xLegend); + } + else{ + return histogramBinsPlot(data, binWidth, binZero, xLegend); + + } + } + + // Distribute data into bins to obtain histogram and plot the histogram + // zero bin position provided + public static double[][] histogramBinsPlot(double[] data, double binWidth, double binZero){ + String xLegend = null; + return histogramBinsPlot(data, binWidth, binZero, xLegend); + } + + // Distribute data into bins to obtain histogram and plot the histogram + // zero bin position and x-axis legend provided + public static double[][] histogramBinsPlot(double[] data, double binWidth, double binZero, String xLegend){ + double[][] results = histogramBins(data, binWidth, binZero); + int nBins = results[0].length; + int nPoints = nBins*3+1; + double[][] cdata = PlotGraph.data(1, nPoints); + cdata[0][0]=binZero; + cdata[1][0]=0.0D; + int k=1; + for(int i=0; i<nBins; i++){ + cdata[0][k]=cdata[0][k-1]; + cdata[1][k]=results[1][i]; + k++; + cdata[0][k]=cdata[0][k-1]+binWidth; + cdata[1][k]=results[1][i]; + k++; + cdata[0][k]=cdata[0][k-1]; + cdata[1][k]=0.0D; + k++; + } + + PlotGraph pg = new PlotGraph(cdata); + pg.setGraphTitle("Histogram: Bin Width = "+binWidth); + pg.setLine(3); + pg.setPoint(0); + pg.setYaxisLegend("Frequency"); + if(xLegend!=null)pg.setXaxisLegend(xLegend); + pg.plot(); + + return results; + } + + // Distribute data into bins to obtain histogram and plot the histogram + // zero bin position calculated + public static double[][] histogramBinsPlot(double[] data, double binWidth){ + String xLegend = null; + return Stat.histogramBinsPlot(data, binWidth, xLegend); + } + + // Distribute data into bins to obtain histogram and plot the histogram + // zero bin position calculated, x-axis legend provided + public static double[][] histogramBinsPlot(double[] data, double binWidth, String xLegend){ + double dmin = Fmath.minimum(data); + double dmax = Fmath.maximum(data); + double span = dmax - dmin; + int nBins = (int) Math.ceil(span/binWidth); + double rem = ((double)nBins)*binWidth-span; + double binZero =dmin-rem/2.0D; + return Stat.histogramBinsPlot(data, binWidth, binZero, xLegend); + } + + + + // UNIFORM ORDER STATISTIC MEDIANS + public static double[] uniformOrderStatisticMedians(int n){ + double nn = (double)n; + double[] uosm = new double[n]; + uosm[n-1] = Math.pow(0.5, 1.0/nn); + uosm[0] = 1.0 - uosm[n-1]; + for(int i=1; i<n-1; i++){ + uosm[i] = (i + 1 - 0.3175)/(nn + 0.365); + } + return uosm; + } + + + + // GAMMA DISTRIBUTION AND GAMMA FUNCTIONS + + // Gamma distribution - three parameter + // Cumulative distribution function + public static double gammaCDF(double mu, double beta, double gamma, double upperLimit){ + if(upperLimit<mu)throw new IllegalArgumentException("The upper limit, " + upperLimit + "must be equal to or greater than the location parameter, " + mu); + if(beta<=0.0D)throw new IllegalArgumentException("The scale parameter, " + beta + "must be greater than zero"); + if(gamma<=0.0D)throw new IllegalArgumentException("The shape parameter, " + gamma + "must be greater than zero"); + double xx = (upperLimit - mu)/beta; + return regularisedGammaFunction(gamma, xx); + } + + // Gamma distribution - standard + // Cumulative distribution function + public static double gammaCDF(double gamma, double upperLimit){ + if(upperLimit<0.0D)throw new IllegalArgumentException("The upper limit, " + upperLimit + "must be equal to or greater than zero"); + if(gamma<=0.0D)throw new IllegalArgumentException("The shape parameter, " + gamma + "must be greater than zero"); + return regularisedGammaFunction(gamma, upperLimit); + } + + // Gamma distribution - three parameter + // probablity density function + public static double gammaPDF(double mu, double beta, double gamma, double x){ + if(x<mu)throw new IllegalArgumentException("The variable, x, " + x + "must be equal to or greater than the location parameter, " + mu); + if(beta<=0.0D)throw new IllegalArgumentException("The scale parameter, " + beta + "must be greater than zero"); + if(gamma<=0.0D)throw new IllegalArgumentException("The shape parameter, " + gamma + "must be greater than zero"); + double xx = (x - mu)/beta; + return Math.pow(xx, gamma-1)*Math.exp(-xx)/(beta*gammaFunction(gamma)); + } + + // Gamma distribution - standard + // probablity density function + public static double gammaPDF(double gamma, double x){ + if(x<0.0D)throw new IllegalArgumentException("The variable, x, " + x + "must be equal to or greater than zero"); + if(gamma<=0.0D)throw new IllegalArgumentException("The shape parameter, " + gamma + "must be greater than zero"); + return Math.pow(x, gamma-1)*Math.exp(-x)/gammaFunction(gamma); + } + + // Gamma distribution - three parameter + // mean + public static double gammaMean(double mu, double beta, double gamma){ + if(beta<=0.0D)throw new IllegalArgumentException("The scale parameter, " + beta + "must be greater than zero"); + if(gamma<=0.0D)throw new IllegalArgumentException("The shape parameter, " + gamma + "must be greater than zero"); + return gamma*beta - mu; + } + + // Gamma distribution - three parameter + // mode + public static double gammaMode(double mu, double beta, double gamma){ + if(beta<=0.0D)throw new IllegalArgumentException("The scale parameter, " + beta + "must be greater than zero"); + if(gamma<=0.0D)throw new IllegalArgumentException("The shape parameter, " + gamma + "must be greater than zero"); + double mode = Double.NaN; + if(gamma>=1.0D)mode = (gamma-1.0D)*beta - mu; + return mode; + } + + // Gamma distribution - three parameter + // standard deviation + public static double gammaStandardDeviation(double mu, double beta, double gamma){ + return gammaStandDev(mu, beta, gamma); + } + + + // Gamma distribution - three parameter + // standard deviation + public static double gammaStandDev(double mu, double beta, double gamma){ + if(beta<=0.0D)throw new IllegalArgumentException("The scale parameter, " + beta + "must be greater than zero"); + if(gamma<=0.0D)throw new IllegalArgumentException("The shape parameter, " + gamma + "must be greater than zero"); + return Math.sqrt(gamma)*beta; + } + + + // Returns an array of Gamma random deviates - clock seed + public static double[] gammaRand(double mu, double beta, double gamma, int n){ + if(beta<=0.0D)throw new IllegalArgumentException("The scale parameter, " + beta + "must be greater than zero"); + if(gamma<=0.0D)throw new IllegalArgumentException("The shape parameter, " + gamma + "must be greater than zero"); + PsRandom psr = new PsRandom(); + return psr.gammaArray(mu, beta, gamma, n); + } + + // Returns an array of Gamma random deviates - user supplied seed + public static double[] gammaRand(double mu, double beta, double gamma, int n, long seed){ + if(beta<=0.0D)throw new IllegalArgumentException("The scale parameter, " + beta + "must be greater than zero"); + if(gamma<=0.0D)throw new IllegalArgumentException("The shape parameter, " + gamma + "must be greater than zero"); + PsRandom psr = new PsRandom(seed); + return psr.gammaArray(mu, beta, gamma, n); + } + + // Gamma function + // Lanczos approximation (6 terms) + public static double gammaFunction(double x){ + + double xcopy = x; + double first = x + lgfGamma + 0.5; + double second = lgfCoeff[0]; + double fg = 0.0D; + + if(x>=0.0){ + if(x>=1.0D && x-(int)x==0.0D){ + fg = Stat.factorial(x)/x; + } + else{ + first = Math.pow(first, x + 0.5)*Math.exp(-first); + for(int i=1; i<=lgfN; i++)second += lgfCoeff[i]/++xcopy; + fg = first*Math.sqrt(2.0*Math.PI)*second/x; + } + } + else{ + fg = -Math.PI/(x*Stat.gamma(-x)*Math.sin(Math.PI*x)); + } + return fg; + } + + // Gamma function + // Lanczos approximation (6 terms) + // retained for backward compatibity + public static double gamma(double x){ + + double xcopy = x; + double first = x + lgfGamma + 0.5; + double second = lgfCoeff[0]; + double fg = 0.0D; + + if(x>=0.0){ + if(x>=1.0D && x-(int)x==0.0D){ + fg = Stat.factorial(x)/x; + } + else{ + first = Math.pow(first, x + 0.5)*Math.exp(-first); + for(int i=1; i<=lgfN; i++)second += lgfCoeff[i]/++xcopy; + fg = first*Math.sqrt(2.0*Math.PI)*second/x; + } + } + else{ + fg = -Math.PI/(x*Stat.gamma(-x)*Math.sin(Math.PI*x)); + } + return fg; + } + + // Return the Lanczos constant gamma + public static double getLanczosGamma(){ + return Stat.lgfGamma; + } + + // Return the Lanczos constant N (number of coeeficients + 1) + public static int getLanczosN(){ + return Stat.lgfN; + } + + // Return the Lanczos coeeficients + public static double[] getLanczosCoeff(){ + int n = Stat.getLanczosN()+1; + double[] coef = new double[n]; + for(int i=0; i<n; i++){ + coef[i] = Stat.lgfCoeff[i]; + } + return coef; + } + + // Return the nearest smallest representable floating point number to zero with mantissa rounded to 1.0 + public static double getFpmin(){ + return Stat.FPMIN; + } + + // log to base e of the Gamma function + // Lanczos approximation (6 terms) + public static double logGammaFunction(double x){ + double xcopy = x; + double fg = 0.0D; + double first = x + lgfGamma + 0.5; + double second = lgfCoeff[0]; + + if(x>=0.0){ + if(x>=1.0 && x-(int)x==0.0){ + fg = Stat.logFactorial(x)-Math.log(x); + } + else{ + first -= (x + 0.5)*Math.log(first); + for(int i=1; i<=lgfN; i++)second += lgfCoeff[i]/++xcopy; + fg = Math.log(Math.sqrt(2.0*Math.PI)*second/x) - first; + } + } + else{ + fg = Math.PI/(Stat.gamma(1.0D-x)*Math.sin(Math.PI*x)); + + if(fg!=1.0/0.0 && fg!=-1.0/0.0){ + if(fg<0){ + throw new IllegalArgumentException("\nThe gamma function is negative"); + } + else{ + fg = Math.log(fg); + } + } + } + return fg; + } + + // log to base e of the Gamma function + // Lanczos approximation (6 terms) + // Retained for backward compatibility + public static double logGamma(double x){ + double xcopy = x; + double fg = 0.0D; + double first = x + lgfGamma + 0.5; + double second = lgfCoeff[0]; + + if(x>=0.0){ + if(x>=1.0 && x-(int)x==0.0){ + fg = Stat.logFactorial(x)-Math.log(x); + } + else{ + first -= (x + 0.5)*Math.log(first); + for(int i=1; i<=lgfN; i++)second += lgfCoeff[i]/++xcopy; + fg = Math.log(Math.sqrt(2.0*Math.PI)*second/x) - first; + } + } + else{ + fg = Math.PI/(Stat.gamma(1.0D-x)*Math.sin(Math.PI*x)); + + if(fg!=1.0/0.0 && fg!=-1.0/0.0){ + if(fg<0){ + throw new IllegalArgumentException("\nThe gamma function is negative"); + } + else{ + fg = Math.log(fg); + } + } + } + return fg; + } + + + // Inverse Gamma Function + public static double[] inverseGammaFunction(double gamma){ + double gammaMinimum = 0.8856031944108839; + double iGammaMinimum = 1.4616321399961483; + if(gamma<gammaMinimum)throw new IllegalArgumentException("Entered argument (gamma) value, " + gamma + ", must be equal to or greater than 0.8856031944108839 - this method does not handle the negative domain"); + + double[] igamma = new double[2]; + + // required tolerance + double tolerance = 1e-12; + + + // x value between 0 and 1.4616321399961483 + if(gamma==1.0){ + igamma[0] = 1.0; + } + else{ + if(gamma==gammaMinimum){ + igamma[0] = iGammaMinimum; + } + else{ + // Create instance of the class holding the gamma inverse function + InverseGammaFunct gif1 = new InverseGammaFunct(); + + // Set inverse gamma function variable + gif1.gamma = gamma; + + // lower bounds + double lowerBound1 = 0.0; + + // upper bound + double upperBound1 = iGammaMinimum; + + // Create instance of RealRoot + RealRoot realR1 = new RealRoot(); + + // Set extension limits + realR1.noBoundsExtensions(); + + // Set tolerance + realR1.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR1.resetNaNexceptionToTrue(); + realR1.supressLimitReachedMessage(); + realR1.supressNaNmessage(); + + // call root searching method + igamma[0] = realR1.bisect(gif1, lowerBound1, upperBound1); + } + } + + // x value above 1.4616321399961483 + if(gamma==1.0){ + igamma[1] = 2.0; + } + else{ + if(gamma==gammaMinimum){ + igamma[1] = iGammaMinimum; + } + else{ + // Create instance of the class holding the gamma inverse function + InverseGammaFunct gif2 = new InverseGammaFunct(); + + // Set inverse gamma function variable + gif2.gamma = gamma; + + // bounds + double lowerBound2 = iGammaMinimum; + double upperBound2 = 2.0; + double ii = 2.0; + double gii = Stat.gamma(ii); + if(gamma>gii){ + boolean test = true; + while(test){ + ii += 1.0; + gii = Stat.gamma(ii); + if(gamma<=gii){ + upperBound2 = ii; + lowerBound2 = ii - 1.0; + test = false; + } + } + } + + // Create instance of RealRoot + RealRoot realR2 = new RealRoot(); + + // Set extension limits + realR2.noBoundsExtensions(); + + // Set tolerance + realR2.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR2.resetNaNexceptionToTrue(); + realR2.supressLimitReachedMessage(); + realR2.supressNaNmessage(); + + // call root searching method + igamma[1] = realR2.bisect(gif2, lowerBound2, upperBound2); + } + } + + return igamma; + } + + // Return Gamma function minimum + // First element contains the Gamma Function minimum value + // Second element contains the x value at which the minimum occors + public static double[] gammaFunctionMinimum(){ + double[] ret = {0.8856031944108839, 1.4616321399961483}; + return ret; + } + + + // Regularised Incomplete Gamma Function P(a,x) = integral from zero to x of (exp(-t)t^(a-1))dt + public static double regularisedGammaFunction(double a, double x){ + if(a<0.0D || x<0.0D)throw new IllegalArgumentException("\nFunction defined only for a >= 0 and x>=0"); + double igf = 0.0D; + + if(x!=0){ + if(x < a+1.0D){ + // Series representation + igf = incompleteGammaSer(a, x); + } + else{ + // Continued fraction representation + igf = incompleteGammaFract(a, x); + } + } + return igf; + } + + // Regularised Incomplete Gamma Function P(a,x) = integral from zero to x of (exp(-t)t^(a-1))dt + public static double regularizedGammaFunction(double a, double x){ + return regularisedGammaFunction(a, x); + } + + // Regularised Incomplete Gamma Function P(a,x) = integral from zero to x of (exp(-t)t^(a-1))dt + // Retained for backward compatibility + public static double regIncompleteGamma(double a, double x){ + return regularisedGammaFunction(a, x); + } + + // Regularised Incomplete Gamma Function P(a,x) = integral from zero to x of (exp(-t)t^(a-1))dt + // Retained for backward compatibility + public static double incompleteGamma(double a, double x){ + return regularisedGammaFunction(a, x); + } + + // Complementary Regularised Incomplete Gamma Function Q(a,x) = 1 - P(a,x) = 1 - integral from zero to x of (exp(-t)t^(a-1))dt + public static double complementaryRegularisedGammaFunction(double a, double x){ + if(a<0.0D || x<0.0D)throw new IllegalArgumentException("\nFunction defined only for a >= 0 and x>=0"); + double igf = 1.0D; + + if(x!=0.0D){ + if(x==1.0D/0.0D) + { + igf=1.0D; + } + else{ + if(x < a+1.0D){ + // Series representation + igf = 1.0D - incompleteGammaSer(a, x); + } + else{ + // Continued fraction representation + igf = 1.0D - incompleteGammaFract(a, x); + } + } + } + return igf; + } + + // Complementary Regularised Incomplete Gamma Function Q(a,x) = 1 - P(a,x) = 1 - integral from zero to x of (exp(-t)t^(a-1))dt + public static double complementaryRegularizedGammaFunction(double a, double x){ + return complementaryRegularisedGammaFunction(a , x); + } + + // Complementary Regularised Incomplete Gamma Function Q(a,x) = 1 - P(a,x) = 1 - integral from zero to x of (exp(-t)t^(a-1))dt + // Retained for backward compatibility + public static double incompleteGammaComplementary(double a, double x){ + return complementaryRegularisedGammaFunction(a , x); + } + + // Complementary Regularised Incomplete Gamma Function Q(a,x) = 1 - P(a,x) = 1 - integral from zero to x of (exp(-t)t^(a-1))dt + // Retained for backward compatibility + public static double regIncompleteGammaComplementary(double a, double x){ + return complementaryRegularisedGammaFunction(a , x); + } + + // Regularised Incomplete Gamma Function P(a,x) = integral from zero to x of (exp(-t)t^(a-1))dt + // Series representation of the function - valid for x < a + 1 + public static double incompleteGammaSer(double a, double x){ + if(a<0.0D || x<0.0D)throw new IllegalArgumentException("\nFunction defined only for a >= 0 and x>=0"); + if(x>=a+1) throw new IllegalArgumentException("\nx >= a+1 use Continued Fraction Representation"); + + double igf = 0.0D; + + if(x!=0.0D){ + + int i = 0; + boolean check = true; + + double acopy = a; + double sum = 1.0/a; + double incr = sum; + double loggamma = Stat.logGamma(a); + + while(check){ + ++i; + ++a; + incr *= x/a; + sum += incr; + if(Math.abs(incr) < Math.abs(sum)*Stat.igfeps){ + igf = sum*Math.exp(-x+acopy*Math.log(x)- loggamma); + check = false; + } + if(i>=Stat.igfiter){ + check=false; + igf = sum*Math.exp(-x+acopy*Math.log(x)- loggamma); + System.out.println("\nMaximum number of iterations were exceeded in Stat.incompleteGammaSer().\nCurrent value returned.\nIncrement = "+String.valueOf(incr)+".\nSum = "+String.valueOf(sum)+".\nTolerance = "+String.valueOf(igfeps)); + } + } + } + + return igf; + } + + // Regularised Incomplete Gamma Function P(a,x) = integral from zero to x of (exp(-t)t^(a-1))dt + // Continued Fraction representation of the function - valid for x >= a + 1 + // This method follows the general procedure used in Numerical Recipes for C, + // The Art of Scientific Computing + // by W H Press, S A Teukolsky, W T Vetterling & B P Flannery + // Cambridge University Press, http://www.nr.com/ + public static double incompleteGammaFract(double a, double x){ + if(a<0.0D || x<0.0D)throw new IllegalArgumentException("\nFunction defined only for a >= 0 and x>=0"); + if(x<a+1) throw new IllegalArgumentException("\nx < a+1 Use Series Representation"); + + double igf = 0.0D; + + if(x!=0.0D){ + + int i = 0; + double ii = 0; + boolean check = true; + + double loggamma = Stat.logGamma(a); + double numer = 0.0D; + double incr = 0.0D; + double denom = x - a + 1.0D; + double first = 1.0D/denom; + double term = 1.0D/FPMIN; + double prod = first; + + while(check){ + ++i; + ii = (double)i; + numer = -ii*(ii - a); + denom += 2.0D; + first = numer*first + denom; + if(Math.abs(first) < Stat.FPMIN){ + first = Stat.FPMIN; + } + term = denom + numer/term; + if(Math.abs(term) < Stat.FPMIN){ + term = Stat.FPMIN; + } + first = 1.0D/first; + incr = first*term; + prod *= incr; + if(Math.abs(incr - 1.0D) < igfeps)check = false; + if(i>=Stat.igfiter){ + check=false; + System.out.println("\nMaximum number of iterations were exceeded in Stat.incompleteGammaFract().\nCurrent value returned.\nIncrement - 1 = "+String.valueOf(incr-1)+".\nTolerance = "+String.valueOf(igfeps)); + } + } + igf = 1.0D - Math.exp(-x+a*Math.log(x)-loggamma)*prod; + } + + return igf; + } + + // Reset the maximum number of iterations allowed in the calculation of the incomplete gamma functions + public static void setIncGammaMaxIter(int igfiter){ + Stat.igfiter=igfiter; + } + + // Return the maximum number of iterations allowed in the calculation of the incomplete gamma functions + public static int getIncGammaMaxIter(){ + return Stat.igfiter; + } + + // Reset the tolerance used in the calculation of the incomplete gamma functions + public static void setIncGammaTol(double igfeps){ + Stat.igfeps=igfeps; + } + + // Return the tolerance used in the calculation of the incomplete gamm functions + public static double getIncGammaTol(){ + return Stat.igfeps; + } + + // FACTORIALS + + // factorial of n + // argument and return are integer, therefore limited to 0<=n<=12 + // see below for long and double arguments + public static int factorial(int n){ + if(n<0)throw new IllegalArgumentException("n must be a positive integer"); + if(n>12)throw new IllegalArgumentException("n must less than 13 to avoid integer overflow\nTry long or double argument"); + int f = 1; + for(int i=2; i<=n; i++)f*=i; + return f; + } + + // factorial of n + // argument and return are long, therefore limited to 0<=n<=20 + // see below for double argument + public static long factorial(long n){ + if(n<0)throw new IllegalArgumentException("n must be a positive integer"); + if(n>20)throw new IllegalArgumentException("n must less than 21 to avoid long integer overflow\nTry double argument"); + long f = 1; + long iCount = 2L; + while(iCount<=n){ + f*=iCount; + iCount += 1L; + } + return f; + } + + // factorial of n + // Argument is of type BigInteger + public static BigInteger factorial(BigInteger n){ + if(n.compareTo(BigInteger.ZERO)==-1)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?"); + BigInteger one = BigInteger.ONE; + BigInteger f = one; + BigInteger iCount = new BigInteger("2"); + while(iCount.compareTo(n)!=1){ + f = f.multiply(iCount); + iCount = iCount.add(one); + } + one = null; + iCount = null; + return f; + } + + // factorial of n + // Argument is of type double but must be, numerically, an integer + // factorial returned as double but is, numerically, should be an integer + // numerical rounding may makes this an approximation after n = 21 + public static double factorial(double n){ + if(n<0 || (n-Math.floor(n))!=0)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?"); + double f = 1.0D; + double iCount = 2.0D; + while(iCount<=n){ + f*=iCount; + iCount += 1.0D; + } + return f; + } + + // factorial of n + // Argument is of type BigDecimal but must be, numerically, an integer + public static BigDecimal factorial(BigDecimal n){ + if(n.compareTo(BigDecimal.ZERO)==-1 || !Fmath.isInteger(n))throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?"); + BigDecimal one = BigDecimal.ONE; + BigDecimal f = one; + BigDecimal iCount = new BigDecimal(2.0D); + while(iCount.compareTo(n)!=1){ + f = f.multiply(iCount); + iCount = iCount.add(one); + } + one = null; + iCount = null; + return f; + } + + + // log to base e of the factorial of n + // log[e](factorial) returned as double + // numerical rounding may makes this an approximation + public static double logFactorial(int n){ + if(n<0)throw new IllegalArgumentException("\nn, " + n + ", must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?"); + double f = 0.0D; + for(int i=2; i<=n; i++)f+=Math.log(i); + return f; + } + + // log to base e of the factorial of n + // Argument is of type double but must be, numerically, an integer + // log[e](factorial) returned as double + // numerical rounding may makes this an approximation + public static double logFactorial(long n){ + if(n<0)throw new IllegalArgumentException("\nn, " + n + ", must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?"); + double f = 0.0D; + long iCount = 2L; + while(iCount<=n){ + f+=Math.log(iCount); + iCount += 1L; + } + return f; + } + + // log to base e of the factorial of n + // Argument is of type double but must be, numerically, an integer + // log[e](factorial) returned as double + // numerical rounding may makes this an approximation + public static double logFactorial(double n){ + if(n<0 || (n-Math.floor(n))!=0)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?"); + double f = 0.0D; + double iCount = 2.0D; + while(iCount<=n){ + f+=Math.log(iCount); + iCount += 1.0D; + } + return f; + } + + + // ERLANG DISTRIBUTION AND ERLANG EQUATIONS + + // Erlang distribution + // Cumulative distribution function + public static double erlangCDF(double lambda, int kay, double upperLimit){ + return gammaCDF(0.0D, 1.0D/lambda, (double)kay, upperLimit); + } + + public static double erlangCDF(double lambda, long kay, double upperLimit){ + return gammaCDF(0.0D, 1.0D/lambda, (double)kay, upperLimit); + } + + public static double erlangCDF(double lambda, double kay, double upperLimit){ + if(kay - Math.round(kay)!=0.0D)throw new IllegalArgumentException("kay must, mathematically, be an integer even though it may be entered as a double\nTry the Gamma distribution instead of the Erlang distribution"); + return gammaCDF(0.0D, 1.0D/lambda, kay, upperLimit); + } + + // Erlang distribution + // probablity density function + public static double erlangPDF(double lambda, int kay, double x){ + return gammaPDF(0.0D, 1.0D/lambda, (double)kay, x); + } + + public static double erlangPDF(double lambda, long kay, double x){ + return gammaPDF(0.0D, 1.0D/lambda, (double)kay, x); + } + + public static double erlangPDF(double lambda, double kay, double x){ + if(kay - Math.round(kay)!=0.0D)throw new IllegalArgumentException("kay must, mathematically, be an integer even though it may be entered as a double\nTry the Gamma distribution instead of the Erlang distribution"); + + return gammaPDF(0.0D, 1.0D/lambda, kay, x); + } + + // Erlang distribution + // mean + public static double erlangMean(double lambda, int kay){ + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + return (double)kay/lambda; + } + + public static double erlangMean(double lambda, long kay){ + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + return (double)kay/lambda; + } + + public static double erlangMean(double lambda, double kay){ + if(kay - Math.round(kay)!=0.0D)throw new IllegalArgumentException("kay must, mathematically, be an integer even though it may be entered as a double\nTry the Gamma distribution instead of the Erlang distribution"); + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + return kay/lambda; + } + + // erlang distribution + // mode + public static double erlangMode(double lambda, int kay){ + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + double mode = Double.NaN; + if(kay>=1)mode = ((double)kay-1.0D)/lambda; + return mode; + } + + public static double erlangMode(double lambda, long kay){ + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + double mode = Double.NaN; + if(kay>=1)mode = ((double)kay-1.0D)/lambda; + return mode; + } + + public static double erlangMode(double lambda, double kay){ + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + if(kay - Math.round(kay)!=0.0D)throw new IllegalArgumentException("kay must, mathematically, be an integer even though it may be entered as a double\nTry the Gamma distribution instead of the Erlang distribution"); + double mode = Double.NaN; + if(kay>=1)mode = (kay-1.0D)/lambda; + return mode; + } + + + // Erlang distribution + // standard deviation + public static double erlangStandardDeviation(double lambda, int kay){ + return erlangStandDev(lambda, kay); + } + + // standard deviation + public static double erlangStandardDeviation(double lambda, long kay){ + return erlangStandDev(lambda, kay); + } + + // standard deviation + public static double erlangStandardDeviation(double lambda, double kay){ + return erlangStandDev(lambda, kay); + } + + // standard deviation + public static double erlangStandDev(double lambda, int kay){ + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + return Math.sqrt((double)kay)/lambda; + } + + public static double erlangStandDev(double lambda, long kay){ + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + return Math.sqrt((double)kay)/lambda; + } + + public static double erlangStandDev(double lambda, double kay){ + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + if(kay - Math.round(kay)!=0.0D)throw new IllegalArgumentException("kay must, mathematically, be an integer even though it may be entered as a double\nTry the Gamma distribution instead of the Erlang distribution"); + return Math.sqrt(kay)/lambda; + } + + // Returns an array of Erlang random deviates - clock seed + public static double[] erlangRand(double lambda, int kay, int n){ + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + return gammaRand(0.0D, 1.0D/lambda, (double) kay, n); + } + + public static double[] erlangRand(double lambda, long kay, int n){ + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + return gammaRand(0.0D, 1.0D/lambda, (double) kay, n); + } + + public static double[] erlangRand(double lambda, double kay, int n){ + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + if(kay - Math.round(kay)!=0.0D)throw new IllegalArgumentException("kay must, mathematically, be an integer even though it may be entered as a double\nTry the Gamma distribution instead of the Erlang distribution"); + return gammaRand(0.0D, 1.0D/lambda, kay, n); + } + + // Returns an array of Erlang random deviates - user supplied seed + public static double[] erlangRand(double lambda, int kay, int n, long seed){ + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + return gammaRand(0.0D, 1.0D/lambda, (double) kay, n, seed); + } + + public static double[] erlangRand(double lambda, long kay, int n, long seed){ + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + return gammaRand(0.0D, 1.0D/lambda, (double) kay, n, seed); + } + + public static double[] erlangRand(double lambda, double kay, int n, long seed){ + if(kay<1)throw new IllegalArgumentException("The rate parameter, " + kay + "must be equal to or greater than one"); + if(kay - Math.round(kay)!=0.0D)throw new IllegalArgumentException("kay must, mathematically, be an integer even though it may be entered as a double\nTry the Gamma distribution instead of the Erlang distribution"); + return gammaRand(0.0D, 1.0D/lambda, kay, n, seed); + } + + + // ERLANG CONNECTIONS BUSY, B AND C EQUATIONS + + // returns the probablility that m resources (connections) are busy + // totalTraffic: total traffic in Erlangs + // totalResouces: total number of resources in the system + public static double erlangMprobability(double totalTraffic, double totalResources, double em){ + double prob = 0.0D; + if(totalTraffic>0.0D){ + + double numer = totalResources*Math.log(em) - Fmath.logFactorial(em); + double denom = 1.0D; + double lastTerm = 1.0D; + for(int i=1; i<=totalResources; i++){ + lastTerm = lastTerm*totalTraffic/(double)i; + denom += lastTerm; + } + denom = Math.log(denom); + prob = numer - denom; + prob = Math.exp(prob); + } + return prob; + } + + public static double erlangMprobability(double totalTraffic, long totalResources, long em){ + return erlangMprobability(totalTraffic, (double)totalResources, (double)em); + } + + public static double erlangMprobability(double totalTraffic, int totalResources, int em){ + return erlangMprobability(totalTraffic, (double)totalResources, (double)em); + } + + // Erlang B equation + // returns the probablility that a customer will be rejected due to lack of resources + // totalTraffic: total traffic in Erlangs + // totalResouces: total number of resources in the system + // recursive calculation + public static double erlangBprobability(double totalTraffic, double totalResources){ + if(totalResources<1)throw new IllegalArgumentException("Total resources, " + totalResources + ", must be an integer greater than or equal to 1"); + if(!Fmath.isInteger(totalResources))throw new IllegalArgumentException("Total resources, " + totalResources + ", must be, arithmetically, an integer"); + double prob = 0.0D; + double iCount = 1.0D; + if(totalTraffic>0.0D){ + prob = 1.0D; + double hold = 0.0; + while(iCount<=totalResources){ + hold = prob*totalTraffic; + prob = hold/(iCount + hold); + iCount += 1.0; + } + } + return prob; + } + + + public static double erlangBprobability(double totalTraffic, long totalResources){ + return erlangBprobability(totalTraffic, (double)totalResources); + } + + public static double erlangBprobability(double totalTraffic, int totalResources){ + return erlangBprobability(totalTraffic, (double)totalResources); + } + + // Erlang B equation + // returns the maximum total traffic in Erlangs + // blockingProbability: probablility that a customer will be rejected due to lack of resources + // totalResouces: total number of resources in the system + public static double erlangBload(double blockingProbability, double totalResources){ + if(totalResources<1)throw new IllegalArgumentException("Total resources, " + totalResources + ", must be an integer greater than or equal to 1"); + if(!Fmath.isInteger(totalResources))throw new IllegalArgumentException("Total resources, " + totalResources + ", must be, arithmetically, an integer"); + + // Create instance of the class holding the Erlang B equation + ErlangBfunct eBfunc = new ErlangBfunct(); + + // Set instance variables + eBfunc.blockingProbability = blockingProbability; + eBfunc.totalResources = totalResources; + + // lower bound + double lowerBound = 0.0D; + // upper bound // arbitrary - may be extended by bisects automatic extension + double upperBound = 20.0; + // required tolerance + double tolerance = 1e-6; + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Set bounds limits + realR.noLowerBoundExtension(); + + // Supress error message if iteration limit reached + realR.supressLimitReachedMessage(); + + // call root searching method + double root = realR.bisect(eBfunc, lowerBound, upperBound); + + return root; + } + + public static double erlangBload(double blockingProbability, long totalResources){ + return erlangBload(blockingProbability, (double)totalResources); + } + + public static double erlangBload(double blockingProbability, int totalResources){ + return erlangBload(blockingProbability, (double)totalResources); + } + + // Erlang B equation + // returns the resources bracketing a blocking probability for a given total traffic + // blockingProbability: probablility that a customer will be rejected due to lack of resources + // totalResouces: total number of resources in the system + public static double[] erlangBresources(double blockingProbability, double totalTraffic){ + + double[] ret = new double[8]; + long counter = 1; + double lastProb = Double.NaN; + double prob = Double.NaN; + boolean test = true; + while(test){ + prob = Stat.erlangBprobability(totalTraffic, counter); + if(prob<=blockingProbability){ + ret[0] = (double)counter; + ret[1] = prob; + ret[2] = Stat.erlangBload(blockingProbability, counter); + ret[3] = (double)(counter-1); + ret[4] = lastProb; + ret[5] = Stat.erlangBload( blockingProbability, counter-1); + ret[6] = blockingProbability; + ret[7] = totalTraffic; + test = false; + } + else{ + lastProb = prob; + counter++; + if(counter==Integer.MAX_VALUE){ + System.out.println("Method erlangBresources: no solution found below " + Long.MAX_VALUE + "resources"); + for(int i=0; i<8; i++)ret[i] = Double.NaN; + test = false; + } + } + } + return ret; + } + + // Erlang C equation + // returns the probablility that a customer will receive a non-zero delay in obtaining obtaining a resource + // totalTraffic: total traffic in Erlangs + // totalResouces: total number of resources in the system + public static double erlangCprobability(double totalTraffic, double totalResources){ + if(totalResources<1)throw new IllegalArgumentException("Total resources, " + totalResources + ", must be an integer greater than or equal to 1"); + if(!Fmath.isInteger(totalResources))throw new IllegalArgumentException("Total resources, " + totalResources + ", must be, arithmetically, an integer"); + + double prob = 0.0D; + if(totalTraffic>0.0D){ + + double numer = totalResources*Math.log(totalTraffic) - Fmath.logFactorial(totalResources); + numer = Math.exp(numer)*totalResources/(totalResources - totalTraffic); + double denom = 1.0D; + double lastTerm = 1.0D; + double iCount = 1.0D; + while(iCount<=totalResources){ + lastTerm = lastTerm*totalTraffic/iCount; + denom += lastTerm; + iCount = iCount + 1.0D; + } + denom += numer; + prob = numer/denom; + } + return prob; + } + + public static double erlangCprobability(double totalTraffic, long totalResources){ + return erlangCprobability(totalTraffic, (double)totalResources); + } + + public static double erlangCprobability(double totalTraffic, int totalResources){ + return erlangCprobability(totalTraffic, (double)totalResources); + } + + // Erlang C equation + // returns the maximum total traffic in Erlangs + // nonZeroDelayProbability: probablility that a customer will receive a non-zero delay in obtaining obtaining a resource + // totalResouces: total number of resources in the system + public static double erlangCload(double nonZeroDelayProbability, double totalResources){ + if(totalResources<1)throw new IllegalArgumentException("Total resources, " + totalResources + ", must be an integer greater than or equal to 1"); + if(!Fmath.isInteger(totalResources))throw new IllegalArgumentException("Total resources, " + totalResources + ", must be, arithmetically, an integer"); + + // Create instance of the class holding the Erlang C equation + ErlangCfunct eCfunc = new ErlangCfunct(); + + // Set instance variables + eCfunc.nonZeroDelayProbability = nonZeroDelayProbability; + eCfunc.totalResources = totalResources; + + // lower bound + double lowerBound = 0.0D; + // upper bound + double upperBound = 10.0D; + // required tolerance + double tolerance = 1e-6; + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error message if iteration limit reached + realR.supressLimitReachedMessage(); + + // Set bounds limits + realR.noLowerBoundExtension(); + + // call root searching method + double root = realR.bisect(eCfunc, lowerBound, upperBound); + + return root; + } + + public static double erlangCload(double nonZeroDelayProbability, long totalResources){ + return erlangCload(nonZeroDelayProbability, (double)totalResources); + } + + public static double erlangCload(double nonZeroDelayProbability, int totalResources){ + return erlangCload(nonZeroDelayProbability, (double)totalResources); + } + + // Erlang C equation + // returns the resources bracketing a non-zer delay probability for a given total traffic + // nonZeroDelayProbability: probablility that a customer will receive a non-zero delay in obtaining obtaining a resource + // totalResouces: total number of resources in the system + public static double[] erlangCresources(double nonZeroDelayProbability, double totalTraffic){ + + double[] ret = new double[8]; + long counter = 1; + double lastProb = Double.NaN; + double prob = Double.NaN; + boolean test = true; + while(test){ + prob = Stat.erlangCprobability(totalTraffic, counter); + if(prob<=nonZeroDelayProbability){ + ret[0] = (double)counter; + ret[1] = prob; + ret[2] = Stat.erlangCload(nonZeroDelayProbability, counter); + ret[3] = (double)(counter-1); + ret[4] = lastProb; + ret[5] = Stat.erlangCload(nonZeroDelayProbability, counter-1); + ret[6] = nonZeroDelayProbability; + ret[7] = totalTraffic; + test = false; + } + else{ + lastProb = prob; + counter++; + if(counter==Integer.MAX_VALUE){ + System.out.println("Method erlangCresources: no solution found below " + Long.MAX_VALUE + "resources"); + for(int i=0; i<8; i++)ret[i] = Double.NaN; + test = false; + } + } + } + return ret; + } + + + + + // ENGSET EQUATION + + // returns the probablility that a customer will be rejected due to lack of resources + // offeredTraffic: total offeredtraffic in Erlangs + // totalResouces: total number of resources in the system + // numberOfSources: number of sources + public static double engsetProbability(double offeredTraffic, double totalResources, double numberOfSources){ + if(totalResources<1)throw new IllegalArgumentException("Total resources, " + totalResources + ", must be an integer greater than or equal to 1"); + if(!Fmath.isInteger(totalResources))throw new IllegalArgumentException("Total resources, " + totalResources + ", must be, arithmetically, an integer"); + if(numberOfSources<1)throw new IllegalArgumentException("number of sources, " + numberOfSources + ", must be an integer greater than or equal to 1"); + if(!Fmath.isInteger(numberOfSources))throw new IllegalArgumentException("number of sources, " + numberOfSources + ", must be, arithmetically, an integer"); + if(totalResources>numberOfSources-1)throw new IllegalArgumentException("total resources, " + totalResources + ", must be less than or equal to the number of sources minus one, " + (numberOfSources - 1)); + if(offeredTraffic>=numberOfSources)throw new IllegalArgumentException("Number of sources, " + numberOfSources + ", must be greater than the offered traffic, " + offeredTraffic); + + double prob = 0.0D; + if(totalResources==0.0D){ + prob = 1.0D; + } + else{ + if(offeredTraffic==0.0D){ + prob = 0.0D; + } + else{ + // Set boundaries to the probability + double lowerBound = 0.0D; + double upperBound = 1.0D; + + // Create instance of Engset Probability Function + EngsetProb engProb = new EngsetProb(); + + // Set function variables + engProb.offeredTraffic = offeredTraffic; + engProb.totalResources = totalResources; + engProb.numberOfSources = numberOfSources; + + // Perform a root search + RealRoot eprt = new RealRoot(); + + // Supress error message if iteration limit reached + eprt.supressLimitReachedMessage(); + + prob = eprt.bisect(engProb, lowerBound, upperBound); + } + } + return prob; + } + + public static double engsetProbability(double offeredTraffic, long totalResources, long numberOfSources){ + return engsetProbability(offeredTraffic, (double)totalResources, (double)numberOfSources); + } + + public static double engsetProbability(double offeredTraffic, int totalResources, int numberOfSources){ + return engsetProbability(offeredTraffic, (double)totalResources, (double)numberOfSources); + } + + // Engset equation + // returns the maximum total traffic in Erlangs + // blockingProbability: probablility that a customer will be rejected due to lack of resources + // totalResouces: total number of resources in the system + // numberOfSources: number of sources + public static double engsetLoad(double blockingProbability, double totalResources, double numberOfSources){ + if(totalResources<1)throw new IllegalArgumentException("Total resources, " + totalResources + ", must be an integer greater than or equal to 1"); + if(!Fmath.isInteger(totalResources))throw new IllegalArgumentException("Total resources, " + totalResources + ", must be, arithmetically, an integer"); + if(numberOfSources<1)throw new IllegalArgumentException("number of sources, " + numberOfSources + ", must be an integer greater than or equal to 1"); + if(!Fmath.isInteger(numberOfSources))throw new IllegalArgumentException("number of sources, " + numberOfSources + ", must be, arithmetically, an integer"); + if(totalResources>numberOfSources-1)throw new IllegalArgumentException("total resources, " + totalResources + ", must be less than or equal to the number of sources minus one, " + (numberOfSources - 1)); + + // Create instance of the class holding the Engset Load equation + EngsetLoad eLfunc = new EngsetLoad(); + + // Set instance variables + eLfunc.blockingProbability = blockingProbability; + eLfunc.totalResources = totalResources; + eLfunc.numberOfSources = numberOfSources; + + // lower bound + double lowerBound = 0.0D; + // upper bound + double upperBound = numberOfSources*0.999999999; + // required tolerance + double tolerance = 1e-6; + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Set bounds limits + realR.noLowerBoundExtension(); + realR.noUpperBoundExtension(); + + // Supress error message if iteration limit reached + realR.supressLimitReachedMessage(); + + // call root searching method + double root = realR.bisect(eLfunc, lowerBound, upperBound); + + return root; + } + + public static double engsetLoad(double blockingProbability, long totalResources, long numberOfSources){ + return engsetLoad(blockingProbability, (double) totalResources, (double) numberOfSources); + } + + public static double engsetLoad(double blockingProbability, int totalResources, int numberOfSources){ + return engsetLoad(blockingProbability, (double) totalResources, (double) numberOfSources); + } + + // Engset equation + // returns the resources bracketing a blocking probability for a given total traffic and number of sources + // blockingProbability: probablility that a customer will be rejected due to lack of resources + // totalResouces: total number of resources in the system + // numberOfSources: number of sources + public static double[] engsetResources(double blockingProbability, double offeredTraffic, double numberOfSources){ + if(numberOfSources<1)throw new IllegalArgumentException("number of sources, " + numberOfSources + ", must be an integer greater than or equal to 1"); + if(!Fmath.isInteger(numberOfSources))throw new IllegalArgumentException("number of sources, " + numberOfSources + ", must be, arithmetically, an integer"); + + double[] ret = new double[9]; + long counter = 1; + double lastProb = Double.NaN; + double prob = Double.NaN; + boolean test = true; + while(test){ + prob = Stat.engsetProbability(offeredTraffic, counter, numberOfSources); + if(prob<=blockingProbability){ + + ret[0] = (double)counter; + ret[1] = prob; + ret[2] = Stat.engsetLoad(blockingProbability, (double)counter, numberOfSources); + ret[3] = (double)(counter-1); + ret[4] = lastProb; + ret[5] = Stat.engsetLoad( blockingProbability, (double)(counter-1), numberOfSources); + ret[6] = blockingProbability; + ret[7] = offeredTraffic; + ret[8] = numberOfSources; + test = false; + } + else{ + lastProb = prob; + counter++; + if(counter>(long)numberOfSources-1L){ + System.out.println("Method engsetResources: no solution found below the (sources-1), " + (numberOfSources-1)); + for(int i=0; i<8; i++)ret[i] = Double.NaN; + test = false; + } + } + } + return ret; + } + + public static double[] engsetResources(double blockingProbability, double totalTraffic, long numberOfSources){ + return Stat.engsetResources(blockingProbability, totalTraffic, (double) numberOfSources); + } + + public static double[] engsetResources(double blockingProbability, double totalTraffic, int numberOfSources){ + return Stat.engsetResources(blockingProbability, totalTraffic, (double) numberOfSources); + } + + + // Engset equation + // returns the number of sources bracketing a blocking probability for a given total traffic and given resources + // blockingProbability: probablility that a customer will be rejected due to lack of resources + // totalResouces: total number of resources in the system + // numberOfSources: number of sources + public static double[] engsetSources(double blockingProbability, double offeredTraffic, double resources){ + if(resources<1)throw new IllegalArgumentException("resources, " + resources + ", must be an integer greater than or equal to 1"); + if(!Fmath.isInteger(resources))throw new IllegalArgumentException("resources, " + resources + ", must be, arithmetically, an integer"); + + double[] ret = new double[9]; + long counter = (long)resources+1L; + double lastProb = Double.NaN; + double prob = Double.NaN; + boolean test = true; + while(test){ + prob = Stat.engsetProbability(offeredTraffic, resources, counter); + if(prob>=blockingProbability){ + + ret[0] = (double)counter; + ret[1] = prob; + ret[2] = Stat.engsetLoad(blockingProbability, resources, (double)counter); + ret[3] = (double)(counter-1L); + ret[4] = lastProb; + if((counter-1L)>=(long)(resources+1L)){ + ret[5] = Stat.engsetLoad(blockingProbability, resources, (double)(counter-1L)); + } + else{ + ret[5] = Double.NaN; + } + ret[6] = blockingProbability; + ret[7] = offeredTraffic; + ret[8] = resources; + test = false; + } + else{ + lastProb = prob; + counter++; + if(counter>=Long.MAX_VALUE){ + System.out.println("Method engsetResources: no solution found below " + Long.MAX_VALUE + "sources"); + for(int i=0; i<8; i++)ret[i] = Double.NaN; + test = false; + } + } + } + return ret; + } + + public static double[] engsetSources(double blockingProbability, double totalTraffic, long resources){ + return Stat.engsetSources(blockingProbability, totalTraffic, (double) resources); + } + + public static double[] engsetSources(double blockingProbability, double totalTraffic, int resources){ + return Stat.engsetSources(blockingProbability, totalTraffic, (double) resources); + } + + + + + // BETA DISTRIBUTIONS AND BETA FUNCTIONS + + // beta distribution cdf + public static double betaCDF(double alpha, double beta, double limit){ + return betaCDF(0.0D, 1.0D, alpha, beta, limit); + } + + // beta distribution pdf + public static double betaCDF(double min, double max, double alpha, double beta, double limit){ + if(alpha<=0.0D)throw new IllegalArgumentException("The shape parameter, alpha, " + alpha + "must be greater than zero"); + if(beta<=0.0D)throw new IllegalArgumentException("The shape parameter, beta, " + beta + "must be greater than zero"); + if(limit<min)throw new IllegalArgumentException("limit, " + limit + ", must be greater than or equal to the minimum value, " + min); + if(limit>max)throw new IllegalArgumentException("limit, " + limit + ", must be less than or equal to the maximum value, " + max); + return Stat.regularisedBetaFunction(alpha, beta, (limit-min)/(max-min)); + } + + + // beta distribution pdf + public static double betaPDF(double alpha, double beta, double x){ + return betaPDF(0.0D, 1.0D, alpha, beta, x); + } + + // beta distribution pdf + public static double betaPDF(double min, double max, double alpha, double beta, double x){ + if(alpha<=0.0D)throw new IllegalArgumentException("The shape parameter, alpha, " + alpha + "must be greater than zero"); + if(beta<=0.0D)throw new IllegalArgumentException("The shape parameter, beta, " + beta + "must be greater than zero"); + if(x<min)throw new IllegalArgumentException("x, " + x + ", must be greater than or equal to the minimum value, " + min); + if(x>max)throw new IllegalArgumentException("x, " + x + ", must be less than or equal to the maximum value, " + max); + double pdf = Math.pow(x - min, alpha - 1)*Math.pow(max - x, beta - 1)/Math.pow(max - min, alpha + beta - 1); + return pdf/Stat.betaFunction(alpha, beta); + } + + // Returns an array of Beta random deviates - clock seed + public static double[] betaRand(double alpha, double beta, int n){ + if(alpha<=0.0D)throw new IllegalArgumentException("The shape parameter, alpha, " + alpha + "must be greater than zero"); + if(beta<=0.0D)throw new IllegalArgumentException("The shape parameter, beta, " + beta + "must be greater than zero"); + PsRandom psr = new PsRandom(); + return psr.betaArray(alpha, beta, n); + } + + // Returns an array of Beta random deviates - clock seed + public static double[] betaRand(double min, double max, double alpha, double beta, int n){ + if(alpha<=0.0D)throw new IllegalArgumentException("The shape parameter, alpha, " + alpha + "must be greater than zero"); + if(beta<=0.0D)throw new IllegalArgumentException("The shape parameter, beta, " + beta + "must be greater than zero"); + PsRandom psr = new PsRandom(); + return psr.betaArray(min, max, alpha, beta, n); + } + + + // Returns an array of Beta random deviates - user supplied seed + public static double[] betaRand(double alpha, double beta, int n, long seed){ + if(alpha<=0.0D)throw new IllegalArgumentException("The shape parameter, alpha, " + alpha + "must be greater than zero"); + if(beta<=0.0D)throw new IllegalArgumentException("The shape parameter, beta, " + beta + "must be greater than zero"); + PsRandom psr = new PsRandom(seed); + return psr.betaArray(alpha, beta, n); + } + + // Returns an array of Beta random deviates - user supplied seed + public static double[] betaRand(double min, double max, double alpha, double beta, int n, long seed){ + if(alpha<=0.0D)throw new IllegalArgumentException("The shape parameter, alpha, " + alpha + "must be greater than zero"); + if(beta<=0.0D)throw new IllegalArgumentException("The shape parameter, beta, " + beta + "must be greater than zero"); + PsRandom psr = new PsRandom(seed); + return psr.betaArray(min, max, alpha, beta, n); + } + + // beta distribution mean + public static double betaMean(double alpha, double beta){ + return betaMean(0.0D, 1.0D, alpha, beta); + } + + // beta distribution mean + public static double betaMean(double min, double max, double alpha, double beta){ + if(alpha<=0.0D)throw new IllegalArgumentException("The shape parameter, alpha, " + alpha + "must be greater than zero"); + if(beta<=0.0D)throw new IllegalArgumentException("The shape parameter, beta, " + beta + "must be greater than zero"); + return min + alpha*(max - min)/(alpha + beta); + } + + // beta distribution mode + public static double betaMode(double alpha, double beta){ + return betaMode(0.0D, 1.0D, alpha, beta); + } + + // beta distribution mode + public static double betaMode(double min, double max, double alpha, double beta){ + if(alpha<=0.0D)throw new IllegalArgumentException("The shape parameter, alpha, " + alpha + "must be greater than zero"); + if(beta<=0.0D)throw new IllegalArgumentException("The shape parameter, beta, " + beta + "must be greater than zero"); + + double mode = Double.NaN; + if(alpha>1){ + if(beta>1){ + mode = min + (alpha + beta)*(max - min)/(alpha + beta - 2); + } + else{ + mode = max; + } + } + else{ + if(alpha==1){ + if(beta>1){ + mode = min; + } + else{ + if(beta==1){ + mode = Double.NaN; + } + else{ + mode = max; + } + } + } + else{ + if(beta>=1){ + mode = min; + } + else{ + System.out.println("Class Stat; method betaMode; distribution is bimodal wirh modes at " + min + " and " + max); + System.out.println("NaN returned"); + } + } + } + return mode; + } + + // beta distribution standard deviation + public static double betaStandardDeviation(double alpha, double beta){ + return betaStandDev(alpha, beta); + } + + // beta distribution standard deviation + public static double betaStandDev(double alpha, double beta){ + return betaStandDev(0.0D, 1.0D, alpha, beta); + } + + // beta distribution standard deviation + public static double betaStandardDeviation(double min, double max, double alpha, double beta){ + return betaStandDev(min, max, alpha, beta); + } + + // beta distribution standard deviation + public static double betaStandDev(double min, double max, double alpha, double beta){ + if(alpha<=0.0D)throw new IllegalArgumentException("The shape parameter, alpha, " + alpha + "must be greater than zero"); + if(beta<=0.0D)throw new IllegalArgumentException("The shape parameter, beta, " + beta + "must be greater than zero"); + return ((max - min)/(alpha + beta))*Math.sqrt(alpha*beta/(alpha + beta + 1)); + } + + // Beta function + public static double betaFunction(double z, double w){ + return Math.exp(logGamma(z) + logGamma(w) - logGamma(z + w)); + } + + // Beta function + // retained for compatibility reasons + public static double beta(double z, double w){ + return Math.exp(logGamma(z) + logGamma(w) - logGamma(z + w)); + } + + // Regularised Incomplete Beta function + // Continued Fraction approximation (see Numerical recipies for details of method) + public static double regularisedBetaFunction(double z, double w, double x){ + if(x<0.0D || x>1.0D)throw new IllegalArgumentException("Argument x, "+x+", must be lie between 0 and 1 (inclusive)"); + double ibeta = 0.0D; + if(x==0.0D){ + ibeta=0.0D; + } + else{ + if(x==1.0D){ + ibeta=1.0D; + } + else{ + // Term before continued fraction + ibeta = Math.exp(Stat.logGamma(z+w) - Stat.logGamma(z) - logGamma(w) + z*Math.log(x) + w*Math.log(1.0D-x)); + // Continued fraction + if(x < (z+1.0D)/(z+w+2.0D)){ + ibeta = ibeta*Stat.contFract(z, w, x)/z; + } + else{ + // Use symmetry relationship + ibeta = 1.0D - ibeta*Stat.contFract(w, z, 1.0D-x)/w; + } + } + } + return ibeta; + } + + + // Regularised Incomplete Beta function + // Continued Fraction approximation (see Numerical recipies for details of method) + public static double regularizedBetaFunction(double z, double w, double x){ + return regularisedBetaFunction(z, w, x); + } + + // Regularised Incomplete Beta function + // Continued Fraction approximation (see Numerical recipies for details of method) + // retained for compatibility reasons + public static double incompleteBeta(double z, double w, double x){ + return regularisedBetaFunction(z, w, x); + } + + // Incomplete fraction summation used in the method regularisedBetaFunction + // modified Lentz's method + public static double contFract(double a, double b, double x){ + int maxit = 500; + double eps = 3.0e-7; + double aplusb = a + b; + double aplus1 = a + 1.0D; + double aminus1 = a - 1.0D; + double c = 1.0D; + double d = 1.0D - aplusb*x/aplus1; + if(Math.abs(d)<Stat.FPMIN)d = FPMIN; + d = 1.0D/d; + double h = d; + double aa = 0.0D; + double del = 0.0D; + int i=1, i2=0; + boolean test=true; + while(test){ + i2=2*i; + aa = i*(b-i)*x/((aminus1+i2)*(a+i2)); + d = 1.0D + aa*d; + if(Math.abs(d)<Stat.FPMIN)d = FPMIN; + c = 1.0D + aa/c; + if(Math.abs(c)<Stat.FPMIN)c = FPMIN; + d = 1.0D/d; + h *= d*c; + aa = -(a+i)*(aplusb+i)*x/((a+i2)*(aplus1+i2)); + d = 1.0D + aa*d; + if(Math.abs(d)<Stat.FPMIN)d = FPMIN; + c = 1.0D + aa/c; + if(Math.abs(c)<Stat.FPMIN)c = FPMIN; + d = 1.0D/d; + del = d*c; + h *= del; + i++; + if(Math.abs(del-1.0D) < eps)test=false; + if(i>maxit){ + test=false; + System.out.println("Maximum number of iterations ("+maxit+") exceeded in Stat.contFract in Stat.incomplete Beta"); + } + } + return h; + + } + + + // ERROR FUNCTIONS + + // Error Function + public static double erf(double x){ + double erf = 0.0D; + if(x!=0.0){ + if(x==1.0D/0.0D){ + erf = 1.0D; + } + else{ + if(x>=0){ + erf = Stat.incompleteGamma(0.5, x*x); + } + else{ + erf = -Stat.incompleteGamma(0.5, x*x); + } + } + } + return erf; + } + + // Complementary Error Function + public static double erfc(double x){ + double erfc = 1.0D; + if(x!=0.0){ + if(x==1.0D/0.0D){ + erfc = 0.0D; + } + else{ + if(x>=0){ + erfc = 1.0D - Stat.incompleteGamma(0.5, x*x); + } + else{ + erfc = 1.0D + Stat.incompleteGamma(0.5, x*x); + } + } + } + return erfc; + } + + + // NORMAL (GAUSSIAN) DISTRIBUTION + + // Gaussian (normal) cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + // mean = the mean, sd = standard deviation + public static double normalCDF(double mean, double sd, double upperlimit){ + double prob = Double.NaN; + if(upperlimit==Double.POSITIVE_INFINITY){ + prob = 1.0; + } + else{ + if(upperlimit==Double.NEGATIVE_INFINITY){ + prob = 0.0; + } + else{ + double arg = (upperlimit - mean)/(sd*Math.sqrt(2.0)); + prob = (1.0D + Stat.erf(arg))/2.0D; + } + } + if(Fmath.isNaN(prob)){ + if(upperlimit>mean){ + prob = 1.0; + } + else{ + prob = 0.0; + } + } + return prob; + } + + // Gaussian (normal) cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + // mean = the mean, sd = standard deviation + public static double normalProb(double mean, double sd, double upperlimit){ + if(upperlimit==Double.POSITIVE_INFINITY){ + return 1.0; + } + else{ + if(upperlimit==Double.NEGATIVE_INFINITY){ + return 0.0; + } + else{ + double arg = (upperlimit - mean)/(sd*Math.sqrt(2.0)); + return (1.0D + Stat.erf(arg))/2.0D; + } + } + } + + // Gaussian (normal) cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + // mean = the mean, sd = standard deviation + public static double gaussianCDF(double mean, double sd, double upperlimit){ + return normalCDF(mean, sd, upperlimit); + } + + // Gaussian (normal) cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + // mean = the mean, sd = standard deviation + public static double gaussianProb(double mean, double sd, double upperlimit){ + return normalCDF(mean, sd, upperlimit); + } + + // Gaussian (normal) cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + // mean = the mean, sd = standard deviation + public static double normalCDF(double mean, double sd, double lowerlimit, double upperlimit){ + return Stat.normalCDF(mean, sd, upperlimit) - Stat.normalCDF(mean, sd, lowerlimit); + } + + // Gaussian (normal) cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + // mean = the mean, sd = standard deviation + public static double normalProb(double mean, double sd, double lowerlimit, double upperlimit){ + return Stat.normalCDF(mean, sd, upperlimit) - Stat.normalCDF(mean, sd, lowerlimit); + } + + // Gaussian (normal) cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + // mean = the mean, sd = standard deviation + public static double gaussianCDF(double mean, double sd, double lowerlimit, double upperlimit){ + return Stat.normalCDF(mean, sd, upperlimit) - Stat.normalCDF(mean, sd, lowerlimit); + } + + // Gaussian (normal) cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + // mean = the mean, sd = standard deviation + public static double gaussianProb(double mean, double sd, double lowerlimit, double upperlimit){ + return Stat.normalCDF(mean, sd, upperlimit) - Stat.normalCDF(mean, sd, lowerlimit); + } + + // Gaussian Inverse Cumulative Distribution Function + public static double gaussianInverseCDF(double mean, double sd, double prob){ + if(prob<0.0 || prob>1.0)throw new IllegalArgumentException("Entered cdf value, " + prob + ", must lie between 0 and 1 inclusive"); + + double icdf = 0.0D; + + if(prob==0.0){ + icdf = Double.NEGATIVE_INFINITY; + } + else{ + if(prob==1.0){ + icdf = Double.POSITIVE_INFINITY; + } + else{ + + // Create instance of the class holding the gaussian cfd function + GaussianFunct gauss = new GaussianFunct(); + + // set function variables + gauss.mean = mean; + gauss.sd = sd; + + // required tolerance + double tolerance = 1e-12; + + // lower bound + double lowerBound = mean - 10.0*sd; + + // upper bound + double upperBound = mean + 10.0*sd; + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + // none + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // set function cfd variable + gauss.cfd = prob; + + // call root searching method + icdf = realR.bisect(gauss, lowerBound, upperBound); + } + } + + return icdf; + } + + // Gaussian Inverse Cumulative Distribution Function + public static double inverseGaussianCDF(double mean, double sd, double prob){ + return gaussianInverseCDF(mean, sd, prob); + } + + // Gaussian Inverse Cumulative Distribution Function + public static double normalInverseCDF(double mean, double sd, double prob){ + return gaussianInverseCDF(mean, sd, prob); + } + + // Gaussian Inverse Cumulative Distribution Function + public static double inverseNormalCDF(double mean, double sd, double prob){ + return gaussianInverseCDF(mean, sd, prob); + } + + // Gaussian Inverse Cumulative Distribution Function + // Standardized + public static double gaussianInverseCDF(double prob){ + return gaussianInverseCDF(0.0D, 1.0D, prob); + } + + // Gaussian Inverse Cumulative Distribution Function + // Standardized + public static double inverseGaussianCDF(double prob){ + return gaussianInverseCDF(0.0D, 1.0D, prob); + } + + // Gaussian Inverse Cumulative Distribution Function + // Standardized + public static double normalInverseCDF(double prob){ + return gaussianInverseCDF(0.0D, 1.0D, prob); + } + + // Gaussian Inverse Cumulative Distribution Function + // Standardized + public static double inverseNormalCDF(double prob){ + return gaussianInverseCDF(0.0D, 1.0D, prob); + } + + + // Gaussian (normal) order statistic medians (n points) + public static double[] gaussianOrderStatisticMedians(double mean, double sigma, int n){ + double nn = (double)n; + double[] gosm = new double[n]; + double[] uosm = uniformOrderStatisticMedians(n); + for(int i=0; i<n; i++){ + gosm[i] =Stat.inverseGaussianCDF(mean, sigma, uosm[i]); + } + gosm = Stat.scale(gosm, mean, sigma); + return gosm; + } + + public static double[] normalOrderStatisticMedians(double mean, double sigma, int n){ + return Stat.gaussianOrderStatisticMedians(mean, sigma, n); + } + + // Gaussian (normal) order statistic medians for a mean of zero and a standard deviation 0f unity (n points) + public static double[] gaussianOrderStatisticMedians(int n){ + return Stat.gaussianOrderStatisticMedians(0.0, 1.0, n); + } + + public static double[] normalOrderStatisticMedians(int n){ + return Stat.gaussianOrderStatisticMedians(0.0, 1.0, n); + } + + // Gaussian (normal) probability density function + // mean = the mean, sd = standard deviation + public static double normalPDF(double mean, double sd, double x){ + return Math.exp(-Fmath.square((x - mean)/sd)/2.0)/(sd*Math.sqrt(2.0D*Math.PI)); + } + + // Gaussian (normal) probability density function + // mean = the mean, sd = standard deviation + public static double normal(double mean, double sd, double x){ + return Math.exp(-Fmath.square((x - mean)/sd)/2.0)/(sd*Math.sqrt(2.0D*Math.PI)); + } + + // Gaussian (normal) probability density function + // mean = the mean, sd = standard deviation + public static double gaussianPDF(double mean, double sd, double x){ + return Math.exp(-Fmath.square((x - mean)/sd)/2.0)/(sd*Math.sqrt(2.0D*Math.PI)); + } + // Gaussian (normal) probability density function + // mean = the mean, sd = standard deviation + public static double gaussian(double mean, double sd, double x){ + return Math.exp(-Fmath.square((x - mean)/sd)/2.0)/(sd*Math.sqrt(2.0D*Math.PI)); + } + + // Returns an array of Gaussian (normal) random deviates - clock seed + // mean = the mean, sd = standard deviation, length of array + public static double[] normalRand(double mean, double sd, int n){ + double[] ran = new double[n]; + Random rr = new Random(); + for(int i=0; i<n; i++){ + ran[i]=rr.nextGaussian(); + } + ran = Stat.standardize(ran); + for(int i=0; i<n; i++){ + ran[i] = ran[i]*sd+mean; + } + return ran; + } + + // Returns an array of Gaussian (normal) random deviates - clock seed + // mean = the mean, sd = standard deviation, length of array + public static double[] gaussianRand(double mean, double sd, int n){ + return normalRand(mean, sd, n); + } + + // Returns an array of Gaussian (normal) random deviates - user provided seed + // mean = the mean, sd = standard deviation, length of array + public static double[] normalRand(double mean, double sd, int n, long seed){ + double[] ran = new double[n]; + Random rr = new Random(seed); + for(int i=0; i<n; i++){ + ran[i]=rr.nextGaussian(); + } + ran = Stat.standardize(ran); + for(int i=0; i<n; i++){ + ran[i] = ran[i]*sd+mean; + } + return ran; + } + + // Returns an array of Gaussian (normal) random deviates - user provided seed + // mean = the mean, sd = standard deviation, length of array + public static double[] gaussianRand(double mean, double sd, int n, long seed){ + return normalRand(mean, sd, n, seed); + } + + + + // LOG-NORMAL DISTRIBUTIONS (TWO AND THEE PARAMETER DISTRIBUTIONS) + + // TWO PARAMETER LOG-NORMAL DISTRIBUTION + + // Two parameter log-normal cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double logNormalCDF(double mu, double sigma, double upperLimit){ + if(sigma<0)throw new IllegalArgumentException("The parameter sigma, " + sigma + ", must be greater than or equal to zero"); + if(upperLimit<=0){ + return 0.0D; + } + else{ + return 0.5D*(1.0D + Stat.erf((Math.log(upperLimit)-mu)/(sigma*Math.sqrt(2)))); + } + } + + public static double logNormalTwoParCDF(double mu, double sigma, double upperLimit){ + return logNormalCDF(mu, sigma, upperLimit); + } + + + // Two parameter log-normal cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double logNormalCDF(double mu, double sigma, double lowerLimit, double upperLimit){ + if(sigma<0)throw new IllegalArgumentException("The parameter sigma, " + sigma + ", must be greater than or equal to zero"); + if(upperLimit<lowerLimit)throw new IllegalArgumentException("The upper limit, " + upperLimit + ", must be greater than the " + lowerLimit); + + double arg1 = 0.0D; + double arg2 = 0.0D; + double cdf = 0.0D; + + if(lowerLimit!=upperLimit){ + if(upperLimit>0.0D)arg1 = 0.5D*(1.0D + Stat.erf((Math.log(upperLimit)-mu)/(sigma*Math.sqrt(2)))); + if(lowerLimit>0.0D)arg2 = 0.5D*(1.0D + Stat.erf((Math.log(lowerLimit)-mu)/(sigma*Math.sqrt(2)))); + cdf = arg1 - arg2; + } + + return cdf; + } + + public static double logNormalTwoParCDF(double mu, double sigma, double lowerLimit, double upperLimit){ + return logNormalCDF(mu, sigma, lowerLimit, upperLimit); + } + + // Log-Normal Inverse Cumulative Distribution Function + // Two parameter + public static double logNormalInverseCDF(double mu, double sigma, double prob){ + double alpha = 0.0; + double beta = sigma; + double gamma = Math.exp(mu); + + return logNormalInverseCDF(alpha, beta, gamma, prob); + } + + // Log-Normal Inverse Cumulative Distribution Function + // Two parameter + public static double logNormaltwoParInverseCDF(double mu, double sigma, double prob){ + double alpha = 0.0; + double beta = sigma; + double gamma = Math.exp(mu); + + return logNormalInverseCDF(alpha, beta, gamma, prob); + } + + + // Two parameter log-normal probability density function + public static double logNormalPDF(double mu, double sigma, double x){ + if(sigma<0)throw new IllegalArgumentException("The parameter sigma, " + sigma + ", must be greater than or equal to zero"); + if(x<0){ + return 0.0D; + } + else{ + return Math.exp(-0.5D*Fmath.square((Math.log(x)- mu)/sigma))/(x*sigma*Math.sqrt(2.0D*Math.PI)); + } + } + + public static double logNormalTwoParPDF(double mu, double sigma, double x){ + return logNormalPDF(mu, sigma, x); + } + + + // Two parameter log-normal mean + public static double logNormalMean(double mu, double sigma){ + return Math.exp(mu + sigma*sigma/2.0D); + } + + public static double logNormalTwoParMean(double mu, double sigma){ + return Math.exp(mu + sigma*sigma/2.0D); + } + + // Two parameter log-normal standard deviation + public static double logNormalStandardDeviation(double mu, double sigma){ + return logNormalStandDev(mu, sigma); + } + + // Two parameter log-normal standard deviation + public static double logNormalStandDev(double mu, double sigma){ + double sigma2 = sigma*sigma; + return Math.sqrt((Math.exp(sigma2) - 1.0D)*Math.exp(2.0D*mu + sigma2)); + } + + public static double logNormalTwoParStandardDeviation(double mu, double sigma){ + return logNormalTwoParStandDev(mu, sigma); + } + + public static double logNormalTwoParStandDev(double mu, double sigma){ + double sigma2 = sigma*sigma; + return Math.sqrt((Math.exp(sigma2) - 1.0D)*Math.exp(2.0D*mu + sigma2)); + } + + // Two parameter log-normal mode + public static double logNormalMode(double mu, double sigma){ + return Math.exp(mu - sigma*sigma); + } + + public static double logNormalTwoParMode(double mu, double sigma){ + return Math.exp(mu - sigma*sigma); + } + + // Two parameter log-normal median + public static double logNormalMedian(double mu){ + return Math.exp(mu); + } + + public static double logNormalTwoParMedian(double mu){ + return Math.exp(mu); + } + + // Returns an array of two parameter log-normal random deviates - clock seed + public static double[] logNormalRand(double mu, double sigma, int n){ + if(n<=0)throw new IllegalArgumentException("The number of random deviates required, " + n + ", must be greater than zero"); + if(sigma<0)throw new IllegalArgumentException("The parameter sigma, " + sigma + ", must be greater than or equal to zero"); + PsRandom psr = new PsRandom(); + return psr.logNormalArray(mu, sigma, n); + } + + public static double[] logNormalTwoParRand(double mu, double sigma, int n){ + return logNormalRand(mu, sigma, n); + } + + // LogNormal order statistic medians (n points) + // Two parametrs + public static double[] logNormalOrderStatisticMedians(double mu, double sigma, int n){ + double alpha = 0.0; + double beta = sigma; + double gamma = Math.exp(mu); + + return logNormalOrderStatisticMedians(alpha, beta, gamma, n); + } + + // LogNormal order statistic medians (n points) + // Two parametrs + public static double[] logNormalTwoParOrderStatisticMedians(double mu, double sigma, int n){ + return Stat.logNormalOrderStatisticMedians(mu, sigma, n); + } + + + // Returns an array of two parameter log-normal random deviates - user supplied seed + public static double[] logNormalRand(double mu, double sigma, int n, long seed){ + if(n<=0)throw new IllegalArgumentException("The number of random deviates required, " + n + ", must be greater than zero"); + if(sigma<0)throw new IllegalArgumentException("The parameter sigma, " + sigma + ", must be greater than or equal to zero"); + PsRandom psr = new PsRandom(seed); + return psr.logNormalArray(mu, sigma, n); + } + + + public static double[] logNormalTwoParRand(double mu, double sigma, int n, long seed){ + return logNormalRand(mu, sigma, n, seed); + } + + // THREE PARAMETER LOG-NORMAL DISTRIBUTION + + // Three parameter log-normal cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double logNormalThreeParCDF(double alpha, double beta, double gamma, double upperLimit){ + if(beta<0)throw new IllegalArgumentException("The parameter beta, " + beta + ", must be greater than or equal to zero"); + if(upperLimit<=alpha){ + return 0.0D; + } + else{ + return 0.5D*(1.0D + Stat.erf(Math.log((upperLimit-alpha)/gamma)/(beta*Math.sqrt(2)))); + } + } + + + // Three parameter log-normal cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double logNormalThreeParCDF(double alpha, double beta, double gamma, double lowerLimit, double upperLimit){ + if(beta<0)throw new IllegalArgumentException("The parameter beta, " + beta + ", must be greater than or equal to zero"); + if(upperLimit<lowerLimit)throw new IllegalArgumentException("The upper limit, " + upperLimit + ", must be greater than the " + lowerLimit); + + double arg1 = 0.0D; + double arg2 = 0.0D; + double cdf = 0.0D; + + if(lowerLimit!=upperLimit){ + if(upperLimit>alpha)arg1 = 0.5D*(1.0D + Stat.erf(Math.log((upperLimit-alpha)/gamma)/(beta*Math.sqrt(2)))); + if(lowerLimit>alpha)arg2 = 0.5D*(1.0D + Stat.erf(Math.log((lowerLimit-alpha)/gamma)/(beta*Math.sqrt(2)))); + cdf = arg1 - arg2; + } + + return cdf; + } + + + // Log-Normal Inverse Cumulative Distribution Function + // Three parameter + public static double logNormalInverseCDF(double alpha, double beta, double gamma, double prob){ + if(prob<0.0 || prob>1.0)throw new IllegalArgumentException("Entered cdf value, " + prob + ", must lie between 0 and 1 inclusive"); + + double icdf = 0.0D; + + if(prob==0.0){ + icdf = alpha; + } + else{ + if(prob==1.0){ + icdf = Double.POSITIVE_INFINITY; + } + else{ + + // Create instance of the class holding the Log-Normal cfd function + LogNormalThreeParFunct lognorm = new LogNormalThreeParFunct(); + + // set function variables + lognorm.alpha = alpha; + lognorm.beta = beta; + lognorm.gamma = gamma; + + // required tolerance + double tolerance = 1e-12; + + // lower bound + double lowerBound = alpha; + + // upper bound + double upperBound = Stat.logNormalThreeParMean(alpha, beta, gamma) + 5.0*Stat.logNormalThreeParStandardDeviation(alpha, beta, gamma); + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + realR.noLowerBoundExtension(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // set function cfd variable + lognorm.cfd = prob; + + // call root searching method + icdf = realR.bisect(lognorm, lowerBound, upperBound); + } + } + + return icdf; + } + + // Log-Normal Inverse Cumulative Distribution Function + // Three parameter + public static double logNormalThreeParInverseCDF(double alpha, double beta, double gamma, double prob){ + return logNormalInverseCDF(alpha, beta, gamma, prob); + } + + + // Three parameter log-normal probability density function + public static double logNormalThreeParPDF(double alpha, double beta, double gamma, double x){ + if(beta<0)throw new IllegalArgumentException("The parameter beta, " + beta + ", must be greater than or equal to zero"); + if(x<=alpha){ + return 0.0D; + } + else{ + return Math.exp(-0.5D*Fmath.square(Math.log((x - alpha)/gamma)/beta))/((x - gamma)*beta*Math.sqrt(2.0D*Math.PI)); + } + } + + + // Returns an array of three parameter log-normal random deviates - clock seed + public static double[] logNormalThreeParRand(double alpha, double beta, double gamma, int n){ + if(n<=0)throw new IllegalArgumentException("The number of random deviates required, " + n + ", must be greater than zero"); + if(beta<0)throw new IllegalArgumentException("The parameter beta, " + beta + ", must be greater than or equal to zero"); + PsRandom psr = new PsRandom(); + return psr.logNormalThreeParArray(alpha, beta, gamma, n); + } + + // Returns an array of three parameter log-normal random deviates - user supplied seed + public static double[] logNormalThreeParRand(double alpha, double beta, double gamma, int n, long seed){ + if(n<=0)throw new IllegalArgumentException("The number of random deviates required, " + n + ", must be greater than zero"); + if(beta<0)throw new IllegalArgumentException("The parameter beta, " + beta + ", must be greater than or equal to zero"); + PsRandom psr = new PsRandom(seed); + return psr.logNormalThreeParArray(alpha, beta, gamma, n); + } + + + // LogNormal order statistic medians (n points) + // Three parametrs + public static double[] logNormalOrderStatisticMedians(double alpha, double beta, double gamma, int n){ + double nn = (double)n; + double[] lnosm = new double[n]; + double[] uosm = uniformOrderStatisticMedians(n); + for(int i=0; i<n; i++){ + lnosm[i] =Stat.logNormalThreeParInverseCDF(alpha, beta, gamma, uosm[i]); + } + lnosm = Stat.scale(lnosm, Stat.logNormalThreeParMean(alpha, beta, gamma), Stat.logNormalThreeParStandardDeviation(alpha, beta, gamma)); + return lnosm; + } + + // LogNormal order statistic medians (n points) + // Three parametrs + public static double[] logNormalThreeParOrderStatisticMedians(double alpha, double beta, double gamma, int n){ + return Stat.logNormalOrderStatisticMedians(alpha, beta, gamma, n); + } + + // Three parameter log-normal mean + public static double logNormalThreeParMean(double alpha, double beta, double gamma){ + return gamma*Math.exp(beta*beta/2.0D) + alpha; + } + + // Three parameter log-normal standard deviation + public static double logNormalThreeParStandardDeviation(double alpha, double beta, double gamma){ + return logNormalThreeParStandDev(alpha, beta, gamma); + } + + // Three parameter log-normal standard deviation + public static double logNormalThreeParStandDev(double alpha, double beta, double gamma){ + double beta2 = beta*beta; + return Math.sqrt((Math.exp(beta2) - 1.0D)*Math.exp(2.0D*Math.log(gamma) + beta2)); + } + + // Three parameter log-normal mode + public static double logNormalThreeParMode(double alpha, double beta, double gamma){ + return gamma*Math.exp(- beta*beta) + alpha; + } + + // Three parameter log-normal median + public static double logNormalThreeParMedian(double alpha, double gamma){ + return gamma + alpha; + } + + + // LOGISTIC DISTRIBUTION + // TWO PARAMETERS (See below for three parameter distribution) + + // Logistic cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + // mu = location parameter, beta = scale parameter + public static double logisticCDF(double mu, double beta, double upperlimit){ + return 0.5D*(1.0D + Math.tanh((upperlimit - mu)/(2.0D*beta))); + } + + // Logistic cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + // mu = location parameter, beta = scale parameter + public static double logisticTwoParCDF(double mu, double beta, double upperlimit){ + return 0.5D*(1.0D + Math.tanh((upperlimit - mu)/(2.0D*beta))); + } + + + // Logistic cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + // mu = location parameter, beta = scale parameter + public static double logisticProb(double mu, double beta, double upperlimit){ + return 0.5D*(1.0D + Math.tanh((upperlimit - mu)/(2.0D*beta))); + } + + + // Logistic cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + // mu = location parameter, beta = scale parameter + public static double logisticCDF(double mu, double beta, double lowerlimit, double upperlimit){ + double arg1 = 0.5D*(1.0D + Math.tanh((lowerlimit - mu)/(2.0D*beta))); + double arg2 = 0.5D*(1.0D + Math.tanh((upperlimit - mu)/(2.0D*beta))); + return arg2 - arg1; + } + + // Logistic cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + // mu = location parameter, beta = scale parameter + public static double logisticTwoParCDF(double mu, double beta, double lowerlimit, double upperlimit){ + double arg1 = 0.5D*(1.0D + Math.tanh((lowerlimit - mu)/(2.0D*beta))); + double arg2 = 0.5D*(1.0D + Math.tanh((upperlimit - mu)/(2.0D*beta))); + return arg2 - arg1; + } + + // Logistic cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + // mu = location parameter, beta = scale parameter + public static double logisticProb(double mu, double beta, double lowerlimit, double upperlimit){ + double arg1 = 0.5D*(1.0D + Math.tanh((lowerlimit - mu)/(2.0D*beta))); + double arg2 = 0.5D*(1.0D + Math.tanh((upperlimit - mu)/(2.0D*beta))); + return arg2 - arg1; + } + + + // Logistic Inverse Cumulative Density Function + public static double logisticTwoParInverseCDF(double mu, double beta, double prob){ + return logisticInverseCDF(mu, beta, prob); + } + + // Logistic Inverse Cumulative Density Function + public static double logisticInverseCDF(double mu, double beta, double prob){ + if(prob<0.0 || prob>1.0)throw new IllegalArgumentException("Entered cdf value, " + prob + ", must lie between 0 and 1 inclusive"); + double icdf = 0.0D; + + if(prob==0.0){ + icdf = Double.NEGATIVE_INFINITY; + } + else{ + if(prob==1.0){ + icdf = Double.POSITIVE_INFINITY; + } + else{ + icdf = mu - beta*Math.log(1.0/prob - 1.0); + } + } + + return icdf; + } + + // Logistic probability density function density function + // mu = location parameter, beta = scale parameter + public static double logisticPDF(double mu, double beta, double x){ + return Fmath.square(Fmath.sech((x - mu)/(2.0D*beta)))/(4.0D*beta); + } + + // Logistic probability density function density function + // mu = location parameter, beta = scale parameter + public static double logisticTwoParPDF(double mu, double beta, double x){ + return Fmath.square(Fmath.sech((x - mu)/(2.0D*beta)))/(4.0D*beta); + } + // Logistic probability density function + // mu = location parameter, beta = scale parameter + public static double logistic(double mu, double beta, double x){ + return Fmath.square(Fmath.sech((x - mu)/(2.0D*beta)))/(4.0D*beta); + } + + // Returns an array of logistic distribution random deviates - clock seed + // mu = location parameter, beta = scale parameter + public static double[] logisticTwoParRand(double mu, double beta, int n){ + return logisticRand(mu, beta, n); + } + + // Returns an array of logistic distribution random deviates - clock seed + // mu = location parameter, beta = scale parameter + public static double[] logisticRand(double mu, double beta, int n){ + double[] ran = new double[n]; + Random rr = new Random(); + for(int i=0; i<n; i++){ + ran[i] = 2.0D*beta*Fmath.atanh(2.0D*rr.nextDouble() - 1.0D) + mu; + } + return ran; + } + + // Returns an array of Logistic random deviates - user provided seed + // mu = location parameter, beta = scale parameter + public static double[] logisticTwoParRand(double mu, double beta, int n, long seed){ + return logisticRand(mu, beta, n, seed); + } + + + // Returns an array of Logistic random deviates - user provided seed + // mu = location parameter, beta = scale parameter + public static double[] logisticRand(double mu, double beta, int n, long seed){ + double[] ran = new double[n]; + Random rr = new Random(seed); + for(int i=0; i<n; i++){ + ran[i] = 2.0D*beta*Fmath.atanh(2.0D*rr.nextDouble() - 1.0D) + mu; + } + return ran; + } + + // Logistic order statistic medians (n points) + public static double[] logisticOrderStatisticMedians(double mu, double beta, int n){ + double nn = (double)n; + double[] losm = new double[n]; + double[] uosm = uniformOrderStatisticMedians(n); + for(int i=0; i<n; i++){ + losm[i] = Stat.logisticInverseCDF(mu, beta, uosm[i]); + } + return losm; + } + + // Logistic order statistic medians (n points) + public static double[] logisticTwoParOrderStatisticMedians(double mu, double beta, int n){ + double nn = (double)n; + double[] losm = new double[n]; + double[] uosm = uniformOrderStatisticMedians(n); + for(int i=0; i<n; i++){ + losm[i] = Stat.logisticInverseCDF(mu, beta, uosm[i]); + } + return losm; + } + + // Logistic distribution mean + public static double logisticMean(double mu){ + return mu; + } + + // Logistic distribution mean + public static double logisticTwoParMean(double mu){ + return mu; + } + + // Logistic distribution standard deviation + public static double logisticStandardDeviation(double beta){ + return logisticStandDev(beta); + } + + // Logistic distribution standard deviation + public static double logisticStandDev(double beta){ + return Math.sqrt(Fmath.square(Math.PI*beta)/3.0D); + } + + // Logistic distribution standard deviation + public static double logisticTwoParStandardDeviation(double beta){ + return Math.sqrt(Fmath.square(Math.PI*beta)/3.0D); + } + + // Logistic distribution mode + public static double logisticMode(double mu){ + return mu; + } + + // Logistic distribution mode + public static double logisticTwoParMode(double mu){ + return mu; + } + + // Logistic distribution median + public static double logisticMedian(double mu){ + return mu; + } + + // Logistic distribution median + public static double logisticTwoParMedian(double mu){ + return mu; + } + + + // LORENTZIAN DISTRIBUTION (CAUCHY DISTRIBUTION) + + // Lorentzian cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double lorentzianProb(double mu, double gamma, double upperlimit){ + double arg = (upperlimit - mu)/(gamma/2.0D); + return (1.0D/Math.PI)*(Math.atan(arg)+Math.PI/2.0); + } + // Lorentzian cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double lorentzianCDF(double mu, double gamma, double lowerlimit, double upperlimit){ + double arg1 = (upperlimit - mu)/(gamma/2.0D); + double arg2 = (lowerlimit - mu)/(gamma/2.0D); + return (1.0D/Math.PI)*(Math.atan(arg1)-Math.atan(arg2)); + } + + // Lorentzian cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double lorentzianProb(double mu, double gamma, double lowerlimit, double upperlimit){ + double arg1 = (upperlimit - mu)/(gamma/2.0D); + double arg2 = (lowerlimit - mu)/(gamma/2.0D); + return (1.0D/Math.PI)*(Math.atan(arg1)-Math.atan(arg2)); + } + + // Lorentzian Inverse Cumulative Density Function + public static double lorentzianInverseCDF(double mu, double gamma, double prob){ + if(prob<0.0 || prob>1.0)throw new IllegalArgumentException("Entered cdf value, " + prob + ", must lie between 0 and 1 inclusive"); + double icdf = 0.0D; + + if(prob==0.0){ + icdf = Double.NEGATIVE_INFINITY; + } + else{ + if(prob==1.0){ + icdf = Double.POSITIVE_INFINITY; + } + else{ + icdf = mu + gamma*Math.tan(Math.PI*(prob - 0.5))/2.0; + } + } + + return icdf; + } + + // Lorentzian probability density function + public static double lorentzianPDF(double mu, double gamma, double x){ + double arg =gamma/2.0D; + return (1.0D/Math.PI)*arg/(Fmath.square(mu-x)+arg*arg); + } + + // Lorentzian probability density function + public static double lorentzian(double mu, double gamma, double x){ + double arg =gamma/2.0D; + return (1.0D/Math.PI)*arg/(Fmath.square(mu-x)+arg*arg); + } + + + // Returns an array of Lorentzian random deviates - clock seed + // mu = the mean, gamma = half-height width, length of array + public static double[] lorentzianRand(double mu, double gamma, int n){ + double[] ran = new double[n]; + Random rr = new Random(); + for(int i=0; i<n; i++){ + ran[i]=Math.tan((rr.nextDouble()-0.5)*Math.PI); + ran[i] = ran[i]*gamma/2.0 + mu; + } + return ran; + } + + // Returns an array of Lorentzian random deviates - user provided seed + // mu = the mean, gamma = half-height width, length of array + public static double[] lorentzianRand(double mu, double gamma, int n, long seed){ + double[] ran = new double[n]; + Random rr = new Random(seed); + for(int i=0; i<n; i++){ + ran[i]=Math.tan((rr.nextDouble()-0.5)*Math.PI); + ran[i] = ran[i]*gamma/2.0 + mu; + } + return ran; + } + + // Lorentzian order statistic medians (n points) + public static double[] lorentzianOrderStatisticMedians(double mu, double gamma, int n){ + double nn = (double)n; + double[] losm = new double[n]; + double[] uosm = uniformOrderStatisticMedians(n); + for(int i=0; i<n; i++){ + losm[i] = Stat.lorentzianInverseCDF(mu, gamma, uosm[i]); + } + return losm; + } + + // POISSON DISTRIBUTION + + // Poisson Cumulative Distribution Function + // probability that a number of Poisson random events will occur between 0 and k (inclusive) + // k is an integer greater than equal to 1 + // mean = mean of the Poisson distribution + public static double poissonCDF(int k, double mean){ + if(k<1)throw new IllegalArgumentException("k must be an integer greater than or equal to 1"); + return Stat.incompleteGammaComplementary((double) k, mean); + } + + // Poisson Cumulative Distribution Function + // probability that a number of Poisson random events will occur between 0 and k (inclusive) + // k is an integer greater than equal to 1 + // mean = mean of the Poisson distribution + public static double poissonProb(int k, double mean){ + if(k<1)throw new IllegalArgumentException("k must be an integer greater than or equal to 1"); + return Stat.incompleteGammaComplementary((double) k, mean); + } + + // Poisson Probability Density Function + // k is an integer greater than or equal to zero + // mean = mean of the Poisson distribution + public static double poissonPDF(int k, double mean){ + if(k<0)throw new IllegalArgumentException("k must be an integer greater than or equal to 0"); + return Math.pow(mean, k)*Math.exp(-mean)/Stat.factorial((double)k); + } + + // Poisson Probability Density Function + // k is an integer greater than or equal to zero + // mean = mean of the Poisson distribution + public static double poisson(int k, double mean){ + if(k<0)throw new IllegalArgumentException("k must be an integer greater than or equal to 0"); + return Math.pow(mean, k)*Math.exp(-mean)/Stat.factorial((double)k); + } + + // Returns an array of Poisson random deviates - clock seed + // mean = the mean, n = length of array + // follows the ideas of Numerical Recipes + public static double[] poissonRand(double mean, int n){ + + Random rr = new Random(); + double[] ran = poissonRandCalc(rr, mean, n); + return ran; + } + + // Returns an array of Poisson random deviates - user provided seed + // mean = the mean, n = length of array + // follows the ideas of Numerical Recipes + public static double[] poissonRand(double mean, int n, long seed){ + + Random rr = new Random(seed); + double[] ran = poissonRandCalc(rr, mean, n); + return ran; + } + + // Calculates and returns an array of Poisson random deviates + private static double[] poissonRandCalc(Random rr, double mean, int n){ + double[] ran = new double[n]; + double oldm = -1.0D; + double expt = 0.0D; + double em = 0.0D; + double term = 0.0D; + double sq = 0.0D; + double lnMean = 0.0D; + double yDev = 0.0D; + + if(mean < 12.0D){ + for(int i=0; i<n; i++){ + if(mean != oldm){ + oldm = mean; + expt = Math.exp(-mean); + } + em = -1.0D; + term = 1.0D; + do{ + ++em; + term *= rr.nextDouble(); + }while(term>expt); + ran[i] = em; + } + } + else{ + for(int i=0; i<n; i++){ + if(mean != oldm){ + oldm = mean; + sq = Math.sqrt(2.0D*mean); + lnMean = Math.log(mean); + expt = lnMean - Stat.logGamma(mean+1.0D); + } + do{ + do{ + yDev = Math.tan(Math.PI*rr.nextDouble()); + em = sq*yDev+mean; + }while(em<0.0D); + em = Math.floor(em); + term = 0.9D*(1.0D+yDev*yDev)*Math.exp(em*lnMean - Stat.logGamma(em+1.0D)-expt); + }while(rr.nextDouble()>term); + ran[i] = em; + } + } + return ran; + } + + + // CHI SQUARE DISTRIBUTION AND CHI SQUARE FUNCTIONS + + // Chi-Square Cumulative Distribution Function + // probability that an observed chi-square value for a correct model should be less than chiSquare + // nu = the degrees of freedom + public static double chiSquareCDF(double chiSquare, int nu){ + if(nu<=0)throw new IllegalArgumentException("The degrees of freedom [nu], " + nu + ", must be greater than zero"); + return Stat.incompleteGamma((double)nu/2.0D, chiSquare/2.0D); + } + + // retained for compatability + public static double chiSquareProb(double chiSquare, int nu){ + if(nu<=0)throw new IllegalArgumentException("The degrees of freedom [nu], " + nu + ", must be greater than zero"); + return Stat.incompleteGamma((double)nu/2.0D, chiSquare/2.0D); + } + + // Chi-Square Probability Density Function + // nu = the degrees of freedom + public static double chiSquarePDF(double chiSquare, int nu){ + if(nu<=0)throw new IllegalArgumentException("The degrees of freedom [nu], " + nu + ", must be greater than zero"); + double dnu = (double) nu; + return Math.pow(0.5D, dnu/2.0D)*Math.pow(chiSquare, dnu/2.0D - 1.0D)*Math.exp(-chiSquare/2.0D)/Stat.gammaFunction(dnu/2.0D); + } + + // Returns an array of Chi-Square random deviates - clock seed + public static double[] chiSquareRand(int nu, int n){ + if(nu<=0)throw new IllegalArgumentException("The degrees of freedom [nu], " + nu + ", must be greater than zero"); + PsRandom psr = new PsRandom(); + return psr.chiSquareArray(nu, n); + } + + + // Returns an array of Chi-Square random deviates - user supplied seed + public static double[] chiSquareRand(int nu, int n, long seed){ + if(nu<=0)throw new IllegalArgumentException("The degrees of freedom [nu], " + nu + ", must be greater than zero"); + PsRandom psr = new PsRandom(seed); + return psr.chiSquareArray(nu, n); + } + + // Chi-Square Distribution Mean + // nu = the degrees of freedom + public static double chiSquareMean(int nu){ + if(nu<=0)throw new IllegalArgumentException("The degrees of freedom [nu], " + nu + ", must be greater than zero"); + return (double)nu; + } + + // Chi-Square Distribution Mean + // nu = the degrees of freedom + public static double chiSquareMode(int nu){ + if(nu<=0)throw new IllegalArgumentException("The degrees of freedom [nu], " + nu + ", must be greater than zero"); + double mode = 0.0D; + if(nu>=2)mode = (double)nu - 2.0D; + return mode; + } + + // Chi-Square Distribution Standard Deviation + // nu = the degrees of freedom + public static double chiSquareStandardDeviation(int nu){ + return chiSquareStandDev(nu); + } + + + // Chi-Square Distribution Standard Deviation + // nu = the degrees of freedom + public static double chiSquareStandDev(int nu){ + if(nu<=0)throw new IllegalArgumentException("The degrees of freedom [nu], " + nu + ", must be greater than zero"); + double dnu = (double) nu; + return Math.sqrt(2.0D*dnu); + } + + // Chi-Square Statistic + public static double chiSquare(double[] observed, double[] expected, double[] variance){ + int nObs = observed.length; + int nExp = expected.length; + int nVar = variance.length; + if(nObs!=nExp)throw new IllegalArgumentException("observed array length does not equal the expected array length"); + if(nObs!=nVar)throw new IllegalArgumentException("observed array length does not equal the variance array length"); + double chi = 0.0D; + for(int i=0; i<nObs; i++){ + chi += Fmath.square(observed[i]-expected[i])/variance[i]; + } + return chi; + } + + // Chi-Square Statistic for Poisson distribution for frequency data + // and Poisson distribution for each bin + // double arguments + public static double chiSquareFreq(double[] observedFreq, double[] expectedFreq){ + int nObs = observedFreq.length; + int nExp = expectedFreq.length; + if(nObs!=nExp)throw new IllegalArgumentException("observed array length does not equal the expected array length"); + double chi = 0.0D; + for(int i=0; i<nObs; i++){ + chi += Fmath.square(observedFreq[i]-expectedFreq[i])/expectedFreq[i]; + } + return chi; + } + + // Chi-Square Statistic for Poisson distribution for frequency data + // and Poisson distribution for each bin + // int arguments + public static double chiSquareFreq(int[] observedFreq, int[] expectedFreq){ + int nObs = observedFreq.length; + int nExp = expectedFreq.length; + if(nObs!=nExp)throw new IllegalArgumentException("observed array length does not equal the expected array length"); + double[] observ = new double[nObs]; + double[] expect = new double[nObs]; + for(int i=0; i<nObs; i++){ + observ[i] = observedFreq[i]; + expect[i] = expectedFreq[i]; + } + + return chiSquareFreq(observ, expect); + } + + + // BINOMIAL DISTRIBUTION AND BINOMIAL COEFFICIENTS + + // Returns the binomial cumulative distribution function + public static double binomialCDF(double p, int n, int k){ + if(p<0.0D || p>1.0D)throw new IllegalArgumentException("\np must lie between 0 and 1"); + if(k<0 || n<0)throw new IllegalArgumentException("\nn and k must be greater than or equal to zero"); + if(k>n)throw new IllegalArgumentException("\nk is greater than n"); + return Stat.regularisedBetaFunction(k, n-k+1, p); + } + // Returns the binomial cumulative distribution function + public static double binomialProb(double p, int n, int k){ + if(p<0.0D || p>1.0D)throw new IllegalArgumentException("\np must lie between 0 and 1"); + if(k<0 || n<0)throw new IllegalArgumentException("\nn and k must be greater than or equal to zero"); + if(k>n)throw new IllegalArgumentException("\nk is greater than n"); + return Stat.regularisedBetaFunction(k, n-k+1, p); + } + + // Returns a binomial mass probabilty function + public static double binomialPDF(double p, int n, int k){ + if(k<0 || n<0)throw new IllegalArgumentException("\nn and k must be greater than or equal to zero"); + if(k>n)throw new IllegalArgumentException("\nk is greater than n"); + return Math.floor(0.5D + Math.exp(Stat.logFactorial(n) - Stat.logFactorial(k) - Stat.logFactorial(n-k)))*Math.pow(p, k)*Math.pow(1.0D - p, n - k); + } + + // Returns a binomial mass probabilty function + public static double binomial(double p, int n, int k){ + if(k<0 || n<0)throw new IllegalArgumentException("\nn and k must be greater than or equal to zero"); + if(k>n)throw new IllegalArgumentException("\nk is greater than n"); + return Math.floor(0.5D + Math.exp(Stat.logFactorial(n) - Stat.logFactorial(k) - Stat.logFactorial(n-k)))*Math.pow(p, k)*Math.pow(1.0D - p, n - k); + } + + // Returns a binomial Coefficient as a double + public static double binomialCoeff(int n, int k){ + if(k<0 || n<0)throw new IllegalArgumentException("\nn and k must be greater than or equal to zero"); + if(k>n)throw new IllegalArgumentException("\nk is greater than n"); + return Math.floor(0.5D + Math.exp(Stat.logFactorial(n) - Stat.logFactorial(k) - Stat.logFactorial(n-k))); + } + + // Returns an array of n Binomial pseudorandom deviates from a binomial - clock seed + // distribution of nTrial trials each of probablity, prob, + // after bndlev Numerical Recipes in C - W.H. Press et al. (Cambridge) + // 2nd edition 1992 p295. + public double[] binomialRand(double prob, int nTrials, int n){ + + if(nTrials<n)throw new IllegalArgumentException("Number of deviates requested, " + n + ", must be less than the number of trials, " + nTrials); + if(prob<0.0D || prob>1.0D)throw new IllegalArgumentException("The probablity provided, " + prob + ", must lie between 0 and 1)"); + + double[] ran = new double[n]; // array of deviates to be returned + Random rr = new Random(); // instance of Random + + double binomialDeviate = 0.0D; // the binomial deviate to be returned + double deviateMean = 0.0D; // mean of deviate to be produced + double testDeviate = 0.0D; // test deviate + double workingProb = 0.0; // working value of the probability + double logProb = 0.0; // working value of the probability + double probOld = -1.0D; // previous value of the working probability + double probC = -1.0D; // complementary value of the working probability + double logProbC = -1.0D; // log of the complementary value of the working probability + int nOld= -1; // previous value of trials counter + double enTrials = 0.0D; // (double) trials counter + double oldGamma = 0.0D; // a previous log Gamma function value + double tanW = 0.0D; // a working tangent + double hold0 = 0.0D; // a working holding variable + int jj; // counter + + double probOriginalValue = prob; + for(int i=0; i<n; i++){ + prob = probOriginalValue; + workingProb=(prob <= 0.5D ? prob : 1.0-prob); // distribution invariant on swapping prob for 1 - prob + deviateMean = nTrials*workingProb; + + if(nTrials < 25) { + // if number of trials greater than 25 use direct method + binomialDeviate=0.0D; + for(jj=1;jj<=nTrials;jj++)if (rr.nextDouble() < workingProb) ++binomialDeviate; + } + else if(deviateMean < 1.0D) { + // if fewer than 1 out of 25 events - Poisson approximation is accurate + double expOfMean=Math.exp(-deviateMean); + testDeviate=1.0D; + for (jj=0;jj<=nTrials;jj++) { + testDeviate *= rr.nextDouble(); + if (testDeviate < expOfMean) break; + } + binomialDeviate=(jj <= nTrials ? jj : nTrials); + + } + else{ + // use rejection method + if(nTrials != nOld) { + // if nTrials has changed compute useful quantities + enTrials = (double)nTrials; + oldGamma = Stat.logGamma(enTrials + 1.0D); + nOld = nTrials; + } + if(workingProb != probOld) { + // if workingProb has changed compute useful quantities + probC = 1.0 - workingProb; + logProb = Math.log(workingProb); + logProbC = Math.log(probC); + probOld = workingProb; + } + + double sq = Math.sqrt(2.0*deviateMean*probC); + do{ + do{ + double angle = Math.PI*rr.nextDouble(); + tanW = Math.tan(angle); + hold0 = sq*tanW + deviateMean; + }while(hold0 < 0.0D || hold0 >= (enTrials + 1.0D)); //rejection test + hold0 = Math.floor(hold0); // integer value distribution + testDeviate = 1.2D*sq*(1.0D + tanW*tanW)*Math.exp(oldGamma - Stat.logGamma(hold0 + 1.0D) - Stat.logGamma(enTrials - hold0 + 1.0D) + hold0*logProb + (enTrials - hold0)*logProbC); + }while(rr.nextDouble() > testDeviate); // rejection test + binomialDeviate=hold0; + } + + if(workingProb != prob) binomialDeviate = nTrials - binomialDeviate; // symmetry transformation + + ran[i] = binomialDeviate; + } + + return ran; + } + + // Returns an array of n Binomial pseudorandom deviates from a binomial - user supplied seed + // distribution of nTrial trials each of probablity, prob, + // after bndlev Numerical Recipes in C - W.H. Press et al. (Cambridge) + // 2nd edition 1992 p295. + public double[] binomialRand(double prob, int nTrials, int n, long seed){ + + if(nTrials<n)throw new IllegalArgumentException("Number of deviates requested, " + n + ", must be less than the number of trials, " + nTrials); + if(prob<0.0D || prob>1.0D)throw new IllegalArgumentException("The probablity provided, " + prob + ", must lie between 0 and 1)"); + + double[] ran = new double[n]; // array of deviates to be returned + Random rr = new Random(seed); // instance of Random + + double binomialDeviate = 0.0D; // the binomial deviate to be returned + double deviateMean = 0.0D; // mean of deviate to be produced + double testDeviate = 0.0D; // test deviate + double workingProb = 0.0; // working value of the probability + double logProb = 0.0; // working value of the probability + double probOld = -1.0D; // previous value of the working probability + double probC = -1.0D; // complementary value of the working probability + double logProbC = -1.0D; // log of the complementary value of the working probability + int nOld= -1; // previous value of trials counter + double enTrials = 0.0D; // (double) trials counter + double oldGamma = 0.0D; // a previous log Gamma function value + double tanW = 0.0D; // a working tangent + double hold0 = 0.0D; // a working holding variable + int jj; // counter + + double probOriginalValue = prob; + for(int i=0; i<n; i++){ + prob = probOriginalValue; + workingProb=(prob <= 0.5D ? prob : 1.0-prob); // distribution invariant on swapping prob for 1 - prob + deviateMean = nTrials*workingProb; + + if(nTrials < 25) { + // if number of trials greater than 25 use direct method + binomialDeviate=0.0D; + for(jj=1;jj<=nTrials;jj++)if (rr.nextDouble() < workingProb) ++binomialDeviate; + } + else if(deviateMean < 1.0D) { + // if fewer than 1 out of 25 events - Poisson approximation is accurate + double expOfMean=Math.exp(-deviateMean); + testDeviate=1.0D; + for (jj=0;jj<=nTrials;jj++) { + testDeviate *= rr.nextDouble(); + if (testDeviate < expOfMean) break; + } + binomialDeviate=(jj <= nTrials ? jj : nTrials); + + } + else{ + // use rejection method + if(nTrials != nOld) { + // if nTrials has changed compute useful quantities + enTrials = (double)nTrials; + oldGamma = Stat.logGamma(enTrials + 1.0D); + nOld = nTrials; + } + if(workingProb != probOld) { + // if workingProb has changed compute useful quantities + probC = 1.0 - workingProb; + logProb = Math.log(workingProb); + logProbC = Math.log(probC); + probOld = workingProb; + } + + double sq = Math.sqrt(2.0*deviateMean*probC); + do{ + do{ + double angle = Math.PI*rr.nextDouble(); + tanW = Math.tan(angle); + hold0 = sq*tanW + deviateMean; + }while(hold0 < 0.0D || hold0 >= (enTrials + 1.0D)); //rejection test + hold0 = Math.floor(hold0); // integer value distribution + testDeviate = 1.2D*sq*(1.0D + tanW*tanW)*Math.exp(oldGamma - Stat.logGamma(hold0 + 1.0D) - Stat.logGamma(enTrials - hold0 + 1.0D) + hold0*logProb + (enTrials - hold0)*logProbC); + }while(rr.nextDouble() > testDeviate); // rejection test + binomialDeviate=hold0; + } + + if(workingProb != prob) binomialDeviate = nTrials - binomialDeviate; // symmetry transformation + + ran[i] = binomialDeviate; + } + + return ran; + } + + + // F-DISTRIBUTION AND F-TEST + + // Returns the F-distribution probabilty for degrees of freedom df1, df2 + // F ratio provided + public static double fCompCDF(double fValue, int df1, int df2){ + if(df1<=0)throw new IllegalArgumentException("the degrees of freedom, nu1, " + df1 + ", must be greater than zero"); + if(df2<=0)throw new IllegalArgumentException("the degrees of freedom, nu2, " + df2 + ", must be greater than zero"); + if(fValue<0)throw new IllegalArgumentException("the F-ratio, " + fValue + ", must be greater than or equal to zero"); + double ddf1 = (double)df1; + double ddf2 = (double)df2; + double x = ddf2/(ddf2+ddf1*fValue); + return Stat.regularisedBetaFunction(df2/2.0D, df1/2.0D, x); + } + + // retained fot compatibility + public static double fTestProb(double fValue, int df1, int df2){ + if(df1<=0)throw new IllegalArgumentException("the degrees of freedom, nu1, " + df1 + ", must be greater than zero"); + if(df2<=0)throw new IllegalArgumentException("the degrees of freedom, nu2, " + df2 + ", must be greater than zero"); + if(fValue<0)throw new IllegalArgumentException("the F-ratio, " + fValue + ", must be greater than or equal to zero"); + double ddf1 = (double)df1; + double ddf2 = (double)df2; + double x = ddf2/(ddf2+ddf1*fValue); + return Stat.regularisedBetaFunction(df2/2.0D, df1/2.0D, x); + } + + // Returns the F-distribution probabilty for degrees of freedom df1, df2 + // numerator and denominator variances provided + public static double fCompCDF(double var1, int df1, double var2, int df2){ + if(df1<=0)throw new IllegalArgumentException("the degrees of freedom, nu1, " + df1 + ", must be greater than zero"); + if(df2<=0)throw new IllegalArgumentException("the degrees of freedom, nu2, " + df2 + ", must be greater than zero"); + if(var1<0)throw new IllegalArgumentException("the variance, var1" + var1 + ", must be greater than or equal to zero"); + if(var1<=0)throw new IllegalArgumentException("the variance, var2" + var2 + ", must be greater than zero"); + double fValue = var1/var2; + double ddf1 = (double)df1; + double ddf2 = (double)df2; + double x = ddf2/(ddf2+ddf1*fValue); + return Stat.regularisedBetaFunction(df2/2.0D, df1/2.0D, x); + } + + // retained fot compatibility + public static double fTestProb(double var1, int df1, double var2, int df2){ + if(df1<=0)throw new IllegalArgumentException("the degrees of freedom, nu1, " + df1 + ", must be greater than zero"); + if(df2<=0)throw new IllegalArgumentException("the degrees of freedom, nu2, " + df2 + ", must be greater than zero"); + if(var1<0)throw new IllegalArgumentException("the variance, var1" + var1 + ", must be greater than or equal to zero"); + if(var1<=0)throw new IllegalArgumentException("the variance, var2" + var2 + ", must be greater than zero"); + double fValue = var1/var2; + double ddf1 = (double)df1; + double ddf2 = (double)df2; + double x = ddf2/(ddf2+ddf1*fValue); + return Stat.regularisedBetaFunction(df2/2.0D, df1/2.0D, x); + } + + + // F-distribution Inverse Cumulative Distribution Function + public static double fDistributionInverseCDF(int nu1, int nu2, double prob){ + if(prob<0.0 || prob>1.0)throw new IllegalArgumentException("Entered cdf value, " + prob + ", must lie between 0 and 1 inclusive"); + + double icdf = 0.0D; + + if(prob==0.0){ + icdf = 0.0; + } + else{ + if(prob==1.0){ + icdf = Double.POSITIVE_INFINITY; + } + else{ + + // Create instance of the class holding the F-distribution cfd function + FdistribtionFunct fdistn = new FdistribtionFunct(); + + // set function variables + fdistn.nu1 = nu1; + fdistn.nu2 = nu2; + + // required tolerance + double tolerance = 1e-12; + + // lower bound + double lowerBound = 0.0; + + // upper bound + double upperBound = 2.0; + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + realR.noLowerBoundExtension(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // set function cfd variable + fdistn.cfd = prob; + + // call root searching method + icdf = realR.bisect(fdistn, lowerBound, upperBound); + } + } + return icdf; + } + + + // F-distribution order statistic medians (n points) + public static double[] fDistributionOrderStatisticMedians(int nu1, int nu2, int n){ + double nn = (double)n; + double[] gosm = new double[n]; + double[] uosm = uniformOrderStatisticMedians(n); + for(int i=0; i<n; i++){ + gosm[i] =Stat.fDistributionInverseCDF(nu1, nu2, uosm[i]); + } + Stat st = new Stat(gosm); + double mean = st.mean(); + double sigma = st.standardDeviation(); + gosm = Stat.scale(gosm, mean, sigma); + return gosm; + } + + + // Returns the F-test value corresponding to a F-distribution probabilty, fProb, + // for degrees of freedom df1, df2 + public static double fTestValueGivenFprob(double fProb, int df1, int df2){ + + // Create an array F-test value array + int fTestsNum = 100; // length of array + double[] fTestValues = new double[fTestsNum]; + fTestValues[0]=0.0001D; // lowest array value + fTestValues[fTestsNum-1]=10000.0D; // highest array value + // calculate array increment - log scale + double diff = (Fmath.log10(fTestValues[fTestsNum-1])-Fmath.log10(fTestValues[0]))/(fTestsNum-1); + // Fill array + for(int i=1; i<fTestsNum-1; i++){ + fTestValues[i] = Math.pow(10.0D,(Fmath.log10(fTestValues[i-1])+diff)); + } + + // calculate F test probability array corresponding to F-test value array + double[] fTestProb = new double[fTestsNum]; + for(int i=0; i<fTestsNum; i++){ + fTestProb[i] = Stat.fTestProb(fTestValues[i], df1, df2); + } + + // calculate F-test value for provided probability + // using bisection procedure + double fTest0 = 0.0D; + double fTest1 = 0.0D; + double fTest2 = 0.0D; + + // find bracket for the F-test probabilities and calculate F-Test value from above arrays + boolean test0 = true; + boolean test1 = true; + int i=0; + int endTest=0; + while(test0){ + if(fProb==fTestProb[i]){ + fTest0=fTestValues[i]; + test0=false; + test1=false; + } + else{ + if(fProb>fTestProb[i]){ + test0=false; + if(i>0){ + fTest1=fTestValues[i-1]; + fTest2=fTestValues[i]; + endTest=-1; + } + else{ + fTest1=fTestValues[i]/10.0D; + fTest2=fTestValues[i]; + } + } + else{ + i++; + if(i>fTestsNum-1){ + test0=false; + fTest1=fTestValues[i-1]; + fTest2=10.0D*fTestValues[i-1]; + endTest=1; + } + } + } + } + + // call bisection method + if(test1)fTest0=fTestBisect(fProb, fTest1, fTest2, df1, df2, endTest); + + return fTest0; + } + + // Bisection procedure for calculating and F-test value corresponding + // to a given F-test probability + private static double fTestBisect(double fProb, double fTestLow, double fTestHigh, int df1, int df2, int endTest){ + + double funcLow = fProb - Stat.fTestProb(fTestLow, df1, df2); + double funcHigh = fProb - Stat.fTestProb(fTestHigh, df1, df2); + double fTestMid = 0.0D; + double funcMid = 0.0; + int nExtensions = 0; + int nIter = 1000; // iterations allowed + double check = fProb*1e-6; // tolerance for bisection + boolean test0 = true; // test for extending bracket + boolean test1 = true; // test for bisection procedure + while(test0){ + if(funcLow*funcHigh>0.0D){ + if(endTest<0){ + nExtensions++; + if(nExtensions>100){ + System.out.println("Class: Stats\nMethod: fTestBisect\nProbability higher than range covered\nF-test value is less than "+fTestLow); + System.out.println("This value was returned"); + fTestMid=fTestLow; + test0=false; + test1=false; + } + fTestLow /= 10.0D; + funcLow = fProb - Stat.fTestProb(fTestLow, df1, df2); + } + else{ + nExtensions++; + if(nExtensions>100){ + System.out.println("Class: Stats\nMethod: fTestBisect\nProbability lower than range covered\nF-test value is greater than "+fTestHigh); + System.out.println("This value was returned"); + fTestMid=fTestHigh; + test0=false; + test1=false; + } + fTestHigh *= 10.0D; + funcHigh = fProb - Stat.fTestProb(fTestHigh, df1, df2); + } + } + else{ + test0=false; + } + + int i=0; + while(test1){ + fTestMid = (fTestLow+fTestHigh)/2.0D; + funcMid = fProb - Stat.fTestProb(fTestMid, df1, df2); + if(Math.abs(funcMid)<check){ + test1=false; + } + else{ + i++; + if(i>nIter){ + System.out.println("Class: Stats\nMethod: fTestBisect\nmaximum number of iterations exceeded\ncurrent value of F-test value returned"); + test1=false; + } + if(funcMid*funcHigh>0){ + funcHigh=funcMid; + fTestHigh=fTestMid; + } + else{ + funcLow=funcMid; + fTestLow=fTestMid; + } + } + } + } + return fTestMid; + } + + // F-distribution pdf + public double fPDF(double fValue, int nu1, int nu2){ + double numer = Math.pow(nu1*fValue, nu1)*Math.pow(nu2, nu2); + double dnu1 = (double)nu1; + double dnu2 = (double)nu2; + numer /= Math.pow(dnu1*fValue+dnu2, dnu1+dnu2); + numer = Math.sqrt(numer); + double denom = fValue*Stat.betaFunction(dnu1/2.0D, dnu2/2.0D); + return numer/denom; + } + + public double fPDF(double var1, int nu1, double var2, int nu2){ + return fPDF(var1/var2, nu1, nu2); + } + + // Returns an array of F-distribution random deviates - clock seed + public static double[] fRand(int nu1, int nu2, int n){ + if(nu1<=0)throw new IllegalArgumentException("The degrees of freedom [nu1], " + nu1 + ", must be greater than zero"); + if(nu2<=0)throw new IllegalArgumentException("The degrees of freedom [nu2], " + nu2 + ", must be greater than zero"); + PsRandom psr = new PsRandom(); + return psr.fArray(nu1, nu2, n); + } + + // Returns an array of F-distribution random deviates - user supplied seed + public static double[] fRand(int nu1, int nu2, int n, long seed){ + if(nu1<=0)throw new IllegalArgumentException("The degrees of freedom [nu1], " + nu1 + ", must be greater than zero"); + if(nu2<=0)throw new IllegalArgumentException("The degrees of freedom [nu2], " + nu2 + ", must be greater than zero"); + PsRandom psr = new PsRandom(seed); + return psr.fArray(nu1, nu2, n); + } + + // STUDENT'S T DISTRIBUTION + + // Returns the Student's t probability density function + public static double studentst(double tValue, int df){ + return studentT(tValue, df); + } + + // Returns the Student's t probability density function + public static double studentT(double tValue, int df){ + double ddf = (double)df; + double dfterm = (ddf + 1.0D)/2.0D; + return ((Stat.gamma(dfterm)/Stat.gamma(ddf/2))/Math.sqrt(ddf*Math.PI))*Math.pow(1.0D + tValue*tValue/ddf, -dfterm); + } + + // Returns the Student's t probability density function + public static double studentstPDF(double tValue, int df){ + return studentTpdf(tValue, df); + } + + // Returns the Student's t probability density function + public static double studentTpdf(double tValue, int df){ + double ddf = (double)df; + double dfterm = (ddf + 1.0D)/2.0D; + return ((Stat.gamma(dfterm)/Stat.gamma(ddf/2))/Math.sqrt(ddf*Math.PI))*Math.pow(1.0D + tValue*tValue/ddf, -dfterm); + } + + // Returns the Student's t probability density function + public static double studentTPDF(double tValue, int df){ + double ddf = (double)df; + double dfterm = (ddf + 1.0D)/2.0D; + return ((Stat.gamma(dfterm)/Stat.gamma(ddf/2))/Math.sqrt(ddf*Math.PI))*Math.pow(1.0D + tValue*tValue/ddf, -dfterm); + } + + + // Returns the Student's t cumulative distribution function probability + public static double studentstCDF(double tValue, int df){ + return studentTcdf(tValue, df); + } + + + // Returns the Student's t cumulative distribution function probability + public static double studentTProb(double tValue, int df){ + if(tValue==Double.POSITIVE_INFINITY){ + return 1.0; + } + else{ + if(tValue==Double.NEGATIVE_INFINITY){ + return 0.0; + } + else{ + double ddf = (double)df; + double x = ddf/(ddf+tValue*tValue); + return 0.5D*(1.0D + (Stat.regularisedBetaFunction(ddf/2.0D, 0.5D, 1) - Stat.regularisedBetaFunction(ddf/2.0D, 0.5D, x))*Fmath.sign(tValue)); + } + } + } + + // Returns the Student's t cumulative distribution function probability + public static double studentTcdf(double tValue, int df){ + if(tValue==Double.POSITIVE_INFINITY){ + return 1.0; + } + else{ + if(tValue==Double.NEGATIVE_INFINITY){ + return 0.0; + } + else{ + double ddf = (double)df; + double x = ddf/(ddf+tValue*tValue); + return 0.5D*(1.0D + (Stat.regularisedBetaFunction(ddf/2.0D, 0.5D, 1) - Stat.regularisedBetaFunction(ddf/2.0D, 0.5D, x))*Fmath.sign(tValue)); + } + } + } + + // Returns the Student's t cumulative distribution function probability + public static double studentTCDF(double tValue, int df){ + if(tValue==Double.POSITIVE_INFINITY){ + return 1.0; + } + else{ + if(tValue==Double.NEGATIVE_INFINITY){ + return 0.0; + } + else{ + double ddf = (double)df; + double x = ddf/(ddf+tValue*tValue); + return 0.5D*(1.0D + (Stat.regularisedBetaFunction(ddf/2.0D, 0.5D, 1) - Stat.regularisedBetaFunction(ddf/2.0D, 0.5D, x))*Fmath.sign(tValue)); + } + } + } + + // Returns the Student's t cumulative distribution function probability + public static double studentTcdf(double tValueLower, double tValueUpper, int df){ + if(tValueUpper==Double.POSITIVE_INFINITY){ + if(tValueLower==Double.NEGATIVE_INFINITY){ + return 1.0; + } + else{ + if(tValueLower==Double.POSITIVE_INFINITY){ + return 0.0; + } + else{ + return (1.0 - Stat.studentTcdf(tValueLower, df)); + } + } + } + else{ + if(tValueLower==Double.NEGATIVE_INFINITY){ + if(tValueUpper==Double.NEGATIVE_INFINITY){ + return 0.0; + } + else{ + return Stat.studentTcdf(tValueUpper, df); + } + } + else{ + return Stat.studentTcdf(tValueUpper, df) - Stat.studentTcdf(tValueLower, df); + } + } + } + + // Returns the P-value for a given Student's t value and degrees of freedom + public static double pValue(double tValue, int df){ + double abst = Math.abs(tValue); + return 1.0 - Stat.studentTcdf(-abst, abst, df); + } + + // Returns the Student's t mean, df = degrees of freedom + public static double studentstMean(int df){ + return studentTmean(df); + } + + // Returns the Student's t mean, df = degrees of freedom + public static double studentTmean(int df){ + double mean = Double.NaN; // mean undefined for df = 1 + if(df>1)mean = 0.0D; + return mean; + } + + // Returns the Student's t median + public static double studentstMedian(){ + return 0.0; + } + + // Returns the Student's t median + public static double studentTmedian(){ + return 0.0; + } + + // Returns the Student's t mode + public static double studentstMode(){ + return 0.0; + } + + // Returns the Student's t mode + public static double studentTmode(){ + return 0.0; + } + + // Returns the Student's t standard deviation, df = degrees of freedom + public static double studentstStandardDeviation(int df){ + return studentTstandDev(df); + } + + // Returns the Student's t standard deviation, df = degrees of freedom + public static double studentTstandDev(int df){ + double standDev = Double.POSITIVE_INFINITY; + if(df>2)standDev = Math.sqrt(df/(1 - df)); + return standDev; + } + + // Returns the A(t|n) distribution probabilty + public static double probAtn(double tValue, int df){ + double ddf = (double)df; + double x = ddf/(ddf+tValue*tValue); + return 1.0D - Stat.regularisedBetaFunction(ddf/2.0D, 0.5D, x); + } + + // Returns an array of Student's t random deviates - clock seed + // nu = the degrees of freedom + public static double[] studentstRand(int nu, int n){ + return studentTRand(nu, n); + } + + // Returns an array of Student's t random deviates - clock seed + // nu = the degrees of freedom + public static double[] studentTRand(int nu, int n){ + PsRandom psr = new PsRandom(); + return psr.studentTarray(nu, n); + } + + // Returns an array of Student's t random deviates - clock seed + // nu = the degrees of freedom + public static double[] studentTrand(int nu, int n){ + PsRandom psr = new PsRandom(); + return psr.studentTarray(nu, n); + } + + // Returns an array of a Student's t random deviates - user supplied seed + // nu = the degrees of freedom + public static double[] studentstRand(int nu, int n, long seed){ + return studentTrand(nu, n, seed); + } + + // Returns an array of a Student's t random deviates - user supplied seed + // nu = the degrees of freedom + public static double[] studentTrand(int nu, int n, long seed){ + PsRandom psr = new PsRandom(seed); + return psr.studentTarray(nu, n); + } + + // Returns an array of a Student's t random deviates - user supplied seed + // nu = the degrees of freedom + public static double[] studentTRand(int nu, int n, long seed){ + PsRandom psr = new PsRandom(seed); + return psr.studentTarray(nu, n); + } + + + // GUMBEL (TYPE I EXTREME VALUE) DISTRIBUTION + + // Minimum Gumbel cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double gumbelMinProbCDF(double mu, double sigma, double upperlimit){ + if(sigma<0.0D)throw new IllegalArgumentException("sigma must be positive"); + double arg = -(upperlimit - mu)/sigma; + return Math.exp(-Math.exp(arg)); + } + + // Minimum Gumbel cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double gumbelMinProb(double mu, double sigma, double upperlimit){ + if(sigma<0.0D)throw new IllegalArgumentException("sigma must be positive"); + double arg = -(upperlimit - mu)/sigma; + return Math.exp(-Math.exp(arg)); + } + + // Maximum Gumbel cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double gumbelMaxCDF(double mu, double sigma, double upperlimit){ + if(sigma<0.0D)throw new IllegalArgumentException("sigma must be positive"); + double arg = -(upperlimit - mu)/sigma; + return 1.0D-Math.exp(-Math.exp(arg)); + } + + // Maximum Gumbel cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double gumbelMaxProb(double mu, double sigma, double upperlimit){ + if(sigma<0.0D)throw new IllegalArgumentException("sigma must be positive"); + double arg = -(upperlimit - mu)/sigma; + return 1.0D-Math.exp(-Math.exp(arg)); + } + + + // Gumbel (maximum order statistic) Inverse Cumulative Density Function + public static double gumbelMaxInverseCDF(double mu, double sigma, double prob){ + if(prob<0.0 || prob>1.0)throw new IllegalArgumentException("Entered cdf value, " + prob + ", must lie between 0 and 1 inclusive"); + double icdf = 0.0D; + + if(prob==0.0){ + icdf = Double.NEGATIVE_INFINITY; + } + else{ + if(prob==1.0){ + icdf = Double.POSITIVE_INFINITY; + } + else{ + icdf = mu - sigma*Math.log(Math.log(1.0/prob)); + } + } + + return icdf; + } + + // Minimum Gumbel cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double gumbelMinCDF(double mu, double sigma, double lowerlimit, double upperlimit){ + if(sigma<0.0D)throw new IllegalArgumentException("sigma must be positive"); + double arg1 = -(lowerlimit - mu)/sigma; + double arg2 = -(upperlimit - mu)/sigma; + double term1 = Math.exp(-Math.exp(arg1)); + double term2 = Math.exp(-Math.exp(arg2)); + return term2-term1; + } + + // Minimum Gumbel cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double gumbelMinProb(double mu, double sigma, double lowerlimit, double upperlimit){ + if(sigma<0.0D)throw new IllegalArgumentException("sigma must be positive"); + double arg1 = -(lowerlimit - mu)/sigma; + double arg2 = -(upperlimit - mu)/sigma; + double term1 = Math.exp(-Math.exp(arg1)); + double term2 = Math.exp(-Math.exp(arg2)); + return term2-term1; + } + + // Maximum Gumbel cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double gumbelMaxCDF(double mu, double sigma, double lowerlimit, double upperlimit){ + if(sigma<0.0D)throw new IllegalArgumentException("sigma must be positive"); + double arg1 = (lowerlimit - mu)/sigma; + double arg2 = (upperlimit - mu)/sigma; + double term1 = -Math.exp(-Math.exp(arg1)); + double term2 = -Math.exp(-Math.exp(arg2)); + return term2-term1; + } + + // Maximum Gumbel cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double gumbelMaxProb(double mu, double sigma, double lowerlimit, double upperlimit){ + if(sigma<0.0D)throw new IllegalArgumentException("sigma must be positive"); + double arg1 = (lowerlimit - mu)/sigma; + double arg2 = (upperlimit - mu)/sigma; + double term1 = -Math.exp(-Math.exp(arg1)); + double term2 = -Math.exp(-Math.exp(arg2)); + return term2-term1; + } + + // Gumbel (minimum order statistic) Inverse Cumulative Density Function + public static double gumbelMinInverseCDF(double mu, double sigma, double prob){ + if(prob<0.0 || prob>1.0)throw new IllegalArgumentException("Entered cdf value, " + prob + ", must lie between 0 and 1 inclusive"); + double icdf = 0.0D; + + if(prob==0.0){ + icdf = Double.NEGATIVE_INFINITY; + } + else{ + if(prob==1.0){ + icdf = Double.POSITIVE_INFINITY; + } + else{ + icdf = mu + sigma*Math.log(Math.log(1.0/(1.0 - prob))); + } + } + + return icdf; + } + + // Minimum Gumbel probability density function + public static double gumbelMinPDF(double mu,double sigma, double x){ + if(sigma<0.0D)throw new IllegalArgumentException("sigma must be positive"); + double arg =(x-mu)/sigma; + return (1.0D/sigma)*Math.exp(arg)*Math.exp(-Math.exp(arg)); + } + + // Minimum Gumbel probability density function + public static double gumbelMin(double mu,double sigma, double x){ + if(sigma<0.0D)throw new IllegalArgumentException("sigma must be positive"); + double arg =(x-mu)/sigma; + return (1.0D/sigma)*Math.exp(arg)*Math.exp(-Math.exp(arg)); + } + + // Maximum Gumbel probability density function + public static double gumbelMaxPDF(double mu,double sigma, double x){ + if(sigma<0.0D)throw new IllegalArgumentException("sigma must be positive"); + double arg =-(x-mu)/sigma; + return (1.0D/sigma)*Math.exp(arg)*Math.exp(-Math.exp(arg)); + } + + // Maximum Gumbel probability density function + public static double gumbelMax(double mu,double sigma, double x){ + if(sigma<0.0D)throw new IllegalArgumentException("sigma must be positive"); + double arg =-(x-mu)/sigma; + return (1.0D/sigma)*Math.exp(arg)*Math.exp(-Math.exp(arg)); + } + + // Returns an array of minimal Gumbel (Type I EVD) random deviates - clock seed + // mu = location parameter, sigma = scale parameter, n = length of array + public static double[] gumbelMinRand(double mu, double sigma, int n){ + double[] ran = new double[n]; + Random rr = new Random(); + for(int i=0; i<n; i++){ + ran[i] = Math.log(Math.log(1.0D/(1.0D-rr.nextDouble())))*sigma+mu; + } + return ran; + } + + // Returns an array of minimal Gumbel (Type I EVD) random deviates - user supplied seed + // mu = location parameter, sigma = scale parameter, n = length of array + public static double[] gumbelMinRand(double mu, double sigma, int n, long seed){ + double[] ran = new double[n]; + Random rr = new Random(seed); + for(int i=0; i<n; i++){ + ran[i] = Math.log(Math.log(1.0D/(1.0D-rr.nextDouble())))*sigma+mu; + } + return ran; + } + + // Returns an array of maximal Gumbel (Type I EVD) random deviates - clock seed + // mu = location parameter, sigma = scale parameter, n = length of array + public static double[] gumbelMaxRand(double mu, double sigma, int n){ + double[] ran = new double[n]; + Random rr = new Random(); + for(int i=0; i<n; i++){ + ran[i] = mu-Math.log(Math.log(1.0D/(1.0D-rr.nextDouble())))*sigma; + } + return ran; + } + + // Returns an array of maximal Gumbel (Type I EVD) random deviates - user supplied seed + // mu = location parameter, sigma = scale parameter, n = length of array + public static double[] gumbelMaxRand(double mu, double sigma, int n, long seed){ + double[] ran = new double[n]; + Random rr = new Random(seed); + for(int i=0; i<n; i++){ + ran[i] = mu-Math.log(Math.log(1.0D/(1.0D-rr.nextDouble())))*sigma; + } + return ran; + } + + // Gumbel (minimum order statistic) order statistic medians (n points) + public static double[] gumbelMinOrderStatisticMedians(double mu, double sigma, int n){ + double nn = (double)n; + double[] gmosm = new double[n]; + double[] uosm = uniformOrderStatisticMedians(n); + for(int i=0; i<n; i++){ + gmosm[i] = Stat.gumbelMinInverseCDF(mu, sigma, uosm[i]); + } + return gmosm; + } + + // Gumbel (maximum order statistic) order statistic medians (n points) + public static double[] gumbelMaxOrderStatisticMedians(double mu, double sigma, int n){ + double nn = (double)n; + double[] gmosm = new double[n]; + double[] uosm = uniformOrderStatisticMedians(n); + for(int i=0; i<n; i++){ + gmosm[i] = Stat.gumbelMaxInverseCDF(mu, sigma, uosm[i]); + } + return gmosm; + } + + // Minimum Gumbel mean + public static double gumbelMinMean(double mu,double sigma){ + return mu - sigma*Fmath.EULER_CONSTANT_GAMMA; + } + + // Maximum Gumbel mean + public static double gumbelMaxMean(double mu,double sigma){ + return mu + sigma*Fmath.EULER_CONSTANT_GAMMA; + } + + // Minimum Gumbel standard deviation + public static double gumbelMinStandardDeviation(double sigma){ + return sigma*Math.PI/Math.sqrt(6.0D); + } + + // Minimum Gumbel standard deviation + public static double gumbelMinStandDev(double sigma){ + return sigma*Math.PI/Math.sqrt(6.0D); + } + + // Maximum Gumbel standard deviation + public static double gumbelMaxStandardDeviation(double sigma){ + return sigma*Math.PI/Math.sqrt(6.0D); + } + + // Maximum Gumbel standard deviation + public static double gumbelMaxStandDev(double sigma){ + return sigma*Math.PI/Math.sqrt(6.0D); + } + + // Minimum Gumbel mode + public static double gumbelMinMode(double mu,double sigma){ + return mu; + } + + // Maximum Gumbel mode + public static double gumbelMaxMode(double mu,double sigma){ + return mu; + } + + // Minimum Gumbel median + public static double gumbelMinMedian(double mu,double sigma){ + return mu + sigma*Math.log(Math.log(2.0D)); + } + + // Maximum Gumbel median + public static double gumbelMaxMedian(double mu,double sigma){ + return mu - sigma*Math.log(Math.log(2.0D)); + } + + + // FRECHET (TYPE II EXTREME VALUE) DISTRIBUTION + + // Frechet cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double frechetProb(double mu, double sigma, double gamma, double upperlimit){ + double arg = (upperlimit - mu)/sigma; + double y = 0.0D; + if(arg>0.0D)y = Math.exp(-Math.pow(arg, -gamma)); + return y; + } + + + // Frechet cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double frechetCDF(double mu, double sigma, double gamma, double lowerlimit, double upperlimit){ + double arg1 = (lowerlimit - mu)/sigma; + double arg2 = (upperlimit - mu)/sigma; + double term1 = 0.0D, term2 = 0.0D; + if(arg1>=0.0D)term1 = Math.exp(-Math.pow(arg1, -gamma)); + if(arg2>=0.0D)term2 = Math.exp(-Math.pow(arg2, -gamma)); + return term2-term1; + } + + // Frechet cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double frechetProb(double mu, double sigma, double gamma, double lowerlimit, double upperlimit){ + double arg1 = (lowerlimit - mu)/sigma; + double arg2 = (upperlimit - mu)/sigma; + double term1 = 0.0D, term2 = 0.0D; + if(arg1>=0.0D)term1 = Math.exp(-Math.pow(arg1, -gamma)); + if(arg2>=0.0D)term2 = Math.exp(-Math.pow(arg2, -gamma)); + return term2-term1; + } + + // Frechet Inverse Cumulative Density Function + // Three parameter + public static double frechetInverseCDF(double mu, double sigma, double gamma, double prob){ + if(prob<0.0 || prob>1.0)throw new IllegalArgumentException("Entered cdf value, " + prob + ", must lie between 0 and 1 inclusive"); + double icdf = 0.0D; + + if(prob==0.0){ + icdf = Double.NEGATIVE_INFINITY; + } + else{ + if(prob==1.0){ + icdf = Double.POSITIVE_INFINITY; + } + else{ + icdf = mu + sigma*Math.pow(Math.log(1.0/prob), -1.0/gamma); + } + } + + return icdf; + } + + // Frechet Inverse Cumulative Density Function + // Two parameter + public static double frechetInverseCDF(double sigma, double gamma, double prob){ + return frechetInverseCDF(0.0D, sigma, gamma, prob); + } + + // Frechet Inverse Cumulative Density Function + // Standard + public static double frechetInverseCDF(double gamma, double prob){ + return frechetInverseCDF(0.0D, 1.0D, gamma, prob); + } + + + // Frechet probability density function + public static double frechetPDF(double mu,double sigma, double gamma, double x){ + double arg =(x-mu)/sigma; + double y = 0.0D; + if(arg>=0.0D){ + y = (gamma/sigma)*Math.pow(arg, -gamma-1.0D)*Math.exp(-Math.pow(arg, -gamma)); + } + return y; + } + + // Frechet probability density function + public static double frechet(double mu,double sigma, double gamma, double x){ + double arg =(x-mu)/sigma; + double y = 0.0D; + if(arg>=0.0D){ + y = (gamma/sigma)*Math.pow(arg, -gamma-1.0D)*Math.exp(-Math.pow(arg, -gamma)); + } + return y; + } + + // Frechet order statistic medians (n points) + // Three parameters + public static double[] frechetOrderStatisticMedians(double mu, double sigma, double gamma, int n){ + double nn = (double)n; + double[] fosm = new double[n]; + double[] uosm = uniformOrderStatisticMedians(n); + for(int i=0; i<n; i++){ + fosm[i] = Stat.frechetInverseCDF(mu, sigma, gamma, uosm[i]); + } + return fosm; + } + + // Frechet order statistic medians (n points) + // Two parameters + public static double[] frechetOrderStatisticMedians(double sigma, double gamma, int n){ + return frechetOrderStatisticMedians(0.0D, sigma, gamma, n); + } + + // Frechet order statistic medians (n points) + // Standard + public static double[] frechetOrderStatisticMedians(double gamma, int n){ + return frechetOrderStatisticMedians(0.0D, 1.0D, gamma, n); + } + + // Frechet mean + public static double frechetMean(double mu,double sigma, double gamma){ + double y = Double.NaN; + if(gamma>1.0D){ + y = mu + sigma*Stat.gamma(1.0D-1.0D/gamma); + } + return y; + } + + // Frechet standard deviation + public static double frechetStandardDeviation(double sigma, double gamma){ + return frechetStandDev(sigma, gamma); + } + + + // Frechet standard deviation + public static double frechetStandDev(double sigma, double gamma){ + double y = Double.NaN; + if(gamma>2.0D){ + y = Stat.gamma(1.0D-2.0D/gamma)-Fmath.square(Stat.gamma(1.0D-1.0D/gamma)); + y = sigma*Math.sqrt(y); + } + return y; + } + + // Frechet mode + public static double frechetMode(double mu,double sigma, double gamma){ + return mu + sigma*Math.pow(gamma/(1.0D+gamma), 1.0D/gamma); + } + + // Returns an array of Frechet (Type II EVD) random deviates - clock seed + // mu = location parameter, sigma = cale parameter, gamma = shape parametern = length of array + public static double[] frechetRand(double mu, double sigma, double gamma, int n){ + double[] ran = new double[n]; + Random rr = new Random(); + for(int i=0; i<n; i++){ + ran[i] = Math.pow((1.0D/(Math.log(1.0D/rr.nextDouble()))),1.0D/gamma)*sigma + mu; + } + return ran; + } + + // Returns an array of Frechet (Type II EVD) random deviates - user supplied seed + // mu = location parameter, sigma = cale parameter, gamma = shape parametern = length of array + public static double[] frechetRand(double mu, double sigma, double gamma, int n, long seed){ + double[] ran = new double[n]; + Random rr = new Random(seed); + for(int i=0; i<n; i++){ + ran[i] = Math.pow((1.0D/(Math.log(1.0D/rr.nextDouble()))),1.0D/gamma)*sigma + mu; + } + return ran; + } + + + // WEIBULL (TYPE III EXTREME VALUE) DISTRIBUTION + + // Weibull cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double weibullCDF(double mu, double sigma, double gamma, double upperlimit){ + double arg = (upperlimit - mu)/sigma; + double y = 0.0D; + if(arg>0.0D)y = 1.0D - Math.exp(-Math.pow(arg, gamma)); + return y; + } + + // Weibull cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double weibullProb(double mu, double sigma, double gamma, double upperlimit){ + double arg = (upperlimit - mu)/sigma; + double y = 0.0D; + if(arg>0.0D)y = 1.0D - Math.exp(-Math.pow(arg, gamma)); + return y; + } + + + // Weibull cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double weibullCDF(double mu, double sigma, double gamma, double lowerlimit, double upperlimit){ + double arg1 = (lowerlimit - mu)/sigma; + double arg2 = (upperlimit - mu)/sigma; + double term1 = 0.0D, term2 = 0.0D; + if(arg1>=0.0D)term1 = -Math.exp(-Math.pow(arg1, gamma)); + if(arg2>=0.0D)term2 = -Math.exp(-Math.pow(arg2, gamma)); + return term2-term1; + } + + // Weibull cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double weibullProb(double mu, double sigma, double gamma, double lowerlimit, double upperlimit){ + double arg1 = (lowerlimit - mu)/sigma; + double arg2 = (upperlimit - mu)/sigma; + double term1 = 0.0D, term2 = 0.0D; + if(arg1>=0.0D)term1 = -Math.exp(-Math.pow(arg1, gamma)); + if(arg2>=0.0D)term2 = -Math.exp(-Math.pow(arg2, gamma)); + return term2-term1; + } + + + // Weibull Inverse Cumulative Density Function + // Three parameter + public static double weibullInverseCDF(double mu, double sigma, double gamma, double prob){ + if(prob<0.0 || prob>1.0)throw new IllegalArgumentException("Entered cdf value, " + prob + ", must lie between 0 and 1 inclusive"); + double icdf = 0.0D; + + if(prob==0.0){ + icdf = mu; + } + else{ + if(prob==1.0){ + icdf = Double.POSITIVE_INFINITY; + } + else{ + icdf = mu + sigma*(Math.pow(-Math.log(1.0 - prob), 1.0/gamma)); + } + } + + return icdf; + } + + // Weibull Inverse Cumulative Disrtibution Function + public static double inverseWeibullCDF(double mu, double sigma, double gamma, double prob){ + return weibullInverseCDF(mu, sigma, gamma, prob); + } + + // Weibull Inverse Cumulative Density Function + // Two parameter + public static double weibullInverseCDF(double sigma, double gamma, double prob){ + return weibullInverseCDF(0.0D, sigma, gamma, prob); + } + + public static double inverseWeibullCDF(double sigma, double gamma, double prob){ + return weibullInverseCDF(0.0, sigma, gamma, prob); + } + + + // Weibull Inverse Cumulative Density Function + // Standard + public static double weibullInverseCDF(double gamma, double prob){ + return weibullInverseCDF(0.0D, 1.0D, gamma, prob); + } + + public static double inverseWeibullCDF(double gamma, double prob){ + return weibullInverseCDF(0.0D, 1.0D, gamma, prob); + } + + // Weibull probability density function + public static double weibullPDF(double mu,double sigma, double gamma, double x){ + double arg =(x-mu)/sigma; + double y = 0.0D; + if(arg>=0.0D){ + y = (gamma/sigma)*Math.pow(arg, gamma-1.0D)*Math.exp(-Math.pow(arg, gamma)); + } + return y; + } + + // Weibull probability density function + public static double weibull(double mu,double sigma, double gamma, double x){ + double arg =(x-mu)/sigma; + double y = 0.0D; + if(arg>=0.0D){ + y = (gamma/sigma)*Math.pow(arg, gamma-1.0D)*Math.exp(-Math.pow(arg, gamma)); + } + return y; + } + + // Weibull mean + public static double weibullMean(double mu,double sigma, double gamma){ + return mu + sigma*Stat.gamma(1.0D/gamma+1.0D); + } + + // Weibull standard deviation + public static double weibullStandardDeviation(double sigma, double gamma){ + return weibullStandDev(sigma, gamma); + } + + + // Weibull standard deviation + public static double weibullStandDev(double sigma, double gamma){ + double y = Stat.gamma(2.0D/gamma+1.0D)-Fmath.square(Stat.gamma(1.0D/gamma+1.0D)); + return sigma*Math.sqrt(y); + } + + // Weibull mode + public static double weibullMode(double mu,double sigma, double gamma){ + double y=mu; + if(gamma>1.0D){ + y = mu + sigma*Math.pow((gamma-1.0D)/gamma, 1.0D/gamma); + } + return y; + } + + // Weibull median + public static double weibullMedian(double mu,double sigma, double gamma){ + return mu + sigma*Math.pow(Math.log(2.0D),1.0D/gamma); + } + + // Returns an array of Weibull (Type III EVD) random deviates - clock seed + // mu = location parameter, sigma = cale parameter, gamma = shape parametern = length of array + public static double[] weibullRand(double mu, double sigma, double gamma, int n){ + double[] ran = new double[n]; + Random rr = new Random(); + for(int i=0; i<n; i++){ + ran[i] = Math.pow(-Math.log(1.0D-rr.nextDouble()),1.0D/gamma)*sigma + mu; + } + return ran; + } + + // Returns an array of Weibull (Type III EVD) random deviates - user supplied seed + // mu = location parameter, sigma = cale parameter, gamma = shape parametern = length of array + public static double[] weibullRand(double mu, double sigma, double gamma, int n, long seed){ + double[] ran = new double[n]; + Random rr = new Random(seed); + for(int i=0; i<n; i++){ + ran[i] = Math.pow(-Math.log(1.0D-rr.nextDouble()),1.0D/gamma)*sigma + mu; + } + return ran; + } + + // Weibull order statistic medians (n points) + // Three parameter + public static double[] weibullOrderStatisticMedians(double mu, double sigma, double gamma, int n){ + double nn = (double)n; + double[] wosm = new double[n]; + double[] uosm = uniformOrderStatisticMedians(n); + for(int i=0; i<n; i++){ + wosm[i] = Stat.inverseWeibullCDF(mu, sigma, gamma, uosm[i]); + } + return wosm; + } + + // Weibull order statistic medians for a mu of zero (n points) + // Two parameter + public static double[] weibullOrderStatisticMedians(double sigma, double gamma, int n){ + return Stat.weibullOrderStatisticMedians(0.0, sigma, gamma, n); + } + + // Weibull order statistic medians for a mu of zero and a sigma of unity (n points) + // Standard + public static double[] weibullOrderStatisticMedians(double gamma, int n){ + return Stat.weibullOrderStatisticMedians(0.0, 1.0, gamma, n); + } + + + // EXPONENTIAL DISTRIBUTION + + // Exponential cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double exponentialCDF(double mu, double sigma, double upperlimit){ + double arg = (upperlimit - mu)/sigma; + double y = 0.0D; + if(arg>0.0D)y = 1.0D - Math.exp(-arg); + return y; + } + + // Exponential cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double exponentialProb(double mu, double sigma, double upperlimit){ + double arg = (upperlimit - mu)/sigma; + double y = 0.0D; + if(arg>0.0D)y = 1.0D - Math.exp(-arg); + return y; + } + + // Exponential cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double exponentialCDF(double mu, double sigma, double lowerlimit, double upperlimit){ + double arg1 = (lowerlimit - mu)/sigma; + double arg2 = (upperlimit - mu)/sigma; + double term1 = 0.0D, term2 = 0.0D; + if(arg1>=0.0D)term1 = -Math.exp(-arg1); + if(arg2>=0.0D)term2 = -Math.exp(-arg2); + return term2-term1; + } + + // Exponential cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double exponentialProb(double mu, double sigma, double lowerlimit, double upperlimit){ + double arg1 = (lowerlimit - mu)/sigma; + double arg2 = (upperlimit - mu)/sigma; + double term1 = 0.0D, term2 = 0.0D; + if(arg1>=0.0D)term1 = -Math.exp(-arg1); + if(arg2>=0.0D)term2 = -Math.exp(-arg2); + return term2-term1; + } + + // Exponential Inverse Cumulative Density Function + public static double exponentialInverseCDF(double mu, double sigma, double prob){ + if(prob<0.0 || prob>1.0)throw new IllegalArgumentException("Entered cdf value, " + prob + ", must lie between 0 and 1 inclusive"); + double icdf = 0.0D; + + if(prob==0.0){ + icdf = mu; + } + else{ + if(prob==1.0){ + icdf = Double.POSITIVE_INFINITY; + } + else{ + icdf = mu - sigma*(Math.log(1.0 - prob)); + } + } + + return icdf; + } + + // Exponential Inverse Cumulative Density Function + public static double inverseExponentialCDF(double mu, double sigma, double prob){ + return exponentialInverseCDF(mu, sigma, prob); + } + + // Exponential probability density function + public static double exponentialPDF(double mu,double sigma, double x){ + double arg =(x-mu)/sigma; + double y = 0.0D; + if(arg>=0.0D){ + y = Math.exp(-arg)/sigma; + } + return y; + } + + // Exponential probability density function + public static double exponential(double mu,double sigma, double x){ + double arg =(x-mu)/sigma; + double y = 0.0D; + if(arg>=0.0D){ + y = Math.exp(-arg)/sigma; + } + return y; + } + + // Exponential mean + public static double exponentialMean(double mu, double sigma){ + return mu + sigma; + } + + // Exponential standard deviation + public static double exponentialStandardDeviation(double sigma){ + return sigma; + } + + // Exponential standard deviation + public static double exponentialStandDev(double sigma){ + return sigma; + } + + + // Exponential mode + public static double exponentialMode(double mu){ + return mu; + } + + // Exponential median + public static double exponentialMedian(double mu,double sigma){ + return mu + sigma*Math.log(2.0D); + } + + // Returns an array of Exponential random deviates - clock seed + // mu = location parameter, sigma = cale parameter, gamma = shape parametern = length of array + public static double[] exponentialRand(double mu, double sigma, int n){ + double[] ran = new double[n]; + Random rr = new Random(); + for(int i=0; i<n; i++){ + ran[i] = mu - Math.log(1.0D-rr.nextDouble())*sigma; + } + return ran; + } + + // Returns an array of Exponential random deviates - user supplied seed + // mu = location parameter, sigma = cale parameter, gamma = shape parametern = length of array + public static double[] exponentialRand(double mu, double sigma, int n, long seed){ + double[] ran = new double[n]; + Random rr = new Random(seed); + for(int i=0; i<n; i++){ + ran[i] = mu - Math.log(1.0D-rr.nextDouble())*sigma; + } + return ran; + } + + // Exponential order statistic medians (n points) + public static double[] exponentialOrderStatisticMedians(double mu, double sigma, int n){ + double nn = (double)n; + double[] eosm = new double[n]; + double[] uosm = uniformOrderStatisticMedians(n); + for(int i=0; i<n; i++){ + eosm[i] = Stat.inverseExponentialCDF(mu, sigma, uosm[i]); + } + return eosm; + } + + + + // RAYLEIGH DISTRIBUTION + + // Rayleigh cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double rayleighCDF(double beta, double upperlimit){ + double arg = (upperlimit)/beta; + double y = 0.0D; + if(arg>0.0D)y = 1.0D - Math.exp(-arg*arg/2.0D); + return y; + } + + // Rayleigh cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double rayleighProb(double beta, double upperlimit){ + double arg = (upperlimit)/beta; + double y = 0.0D; + if(arg>0.0D)y = 1.0D - Math.exp(-arg*arg/2.0D); + return y; + } + + // Rayleigh cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double rayleighCDF(double beta, double lowerlimit, double upperlimit){ + double arg1 = (lowerlimit)/beta; + double arg2 = (upperlimit)/beta; + double term1 = 0.0D, term2 = 0.0D; + if(arg1>=0.0D)term1 = -Math.exp(-arg1*arg1/2.0D); + if(arg2>=0.0D)term2 = -Math.exp(-arg2*arg2/2.0D); + return term2-term1; + } + + // Rayleigh cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double rayleighProb(double beta, double lowerlimit, double upperlimit){ + double arg1 = (lowerlimit)/beta; + double arg2 = (upperlimit)/beta; + double term1 = 0.0D, term2 = 0.0D; + if(arg1>=0.0D)term1 = -Math.exp(-arg1*arg1/2.0D); + if(arg2>=0.0D)term2 = -Math.exp(-arg2*arg2/2.0D); + return term2-term1; + } + + // Rayleigh Inverse Cumulative Density Function + public static double rayleighInverseCDF(double beta, double prob){ + if(prob<0.0 || prob>1.0)throw new IllegalArgumentException("Entered cdf value, " + prob + ", must lie between 0 and 1 inclusive"); + double icdf = 0.0D; + + if(prob==0.0){ + icdf = 0.0; + } + else{ + if(prob==1.0){ + icdf = Double.POSITIVE_INFINITY; + } + else{ + icdf = beta*(Math.sqrt(-Math.log(1.0 - prob))); + } + } + + return icdf; + } + + // Rayleigh Inverse Cumulative Density Function + public static double inverseRayleighCDF(double beta, double prob){ + return rayleighInverseCDF(beta, prob); + } + + + // Rayleigh probability density function + public static double rayleighPDF(double beta, double x){ + double arg =x/beta; + double y = 0.0D; + if(arg>=0.0D){ + y = (arg/beta)*Math.exp(-arg*arg/2.0D)/beta; + } + return y; + } + + // Rayleigh probability density function + public static double rayleigh(double beta, double x){ + double arg =x/beta; + double y = 0.0D; + if(arg>=0.0D){ + y = (arg/beta)*Math.exp(-arg*arg/2.0D)/beta; + } + return y; + } + + // Rayleigh mean + public static double rayleighMean(double beta){ + return beta*Math.sqrt(Math.PI/2.0D); + } + + // Rayleigh standard deviation + public static double rayleighStandardDeviation(double beta){ + return beta*Math.sqrt(2.0D-Math.PI/2.0D); + } + + // Rayleigh standard deviation + public static double rayleighStandDev(double beta){ + return beta*Math.sqrt(2.0D-Math.PI/2.0D); + } + + // Rayleigh mode + public static double rayleighMode(double beta){ + return beta; + } + + // Rayleigh median + public static double rayleighMedian(double beta){ + return beta*Math.sqrt(Math.log(2.0D)); + } + + // Returns an array of Rayleigh random deviates - clock seed + // beta = scale parameter, n = length of array + public static double[] rayleighRand(double beta, int n){ + double[] ran = new double[n]; + Random rr = new Random(); + for(int i=0; i<n; i++){ + ran[i] = Math.sqrt(-2.0D*Math.log(1.0D-rr.nextDouble()))*beta; + } + return ran; + } + + // Returns an array of Rayleigh random deviates - user supplied seed + // beta = scale parameter, n = length of array + public static double[] rayleighRand(double beta, int n, long seed){ + double[] ran = new double[n]; + Random rr = new Random(seed); + for(int i=0; i<n; i++){ + ran[i] = Math.sqrt(-2.0D*Math.log(1.0D-rr.nextDouble()))*beta; + } + return ran; + } + + // Rayleigh order statistic medians (n points) + public static double[] rayleighOrderStatisticMedians(double beta, int n){ + double nn = (double)n; + double[] rosm = new double[n]; + double[] uosm = uniformOrderStatisticMedians(n); + for(int i=0; i<n; i++){ + rosm[i] = Stat.inverseRayleighCDF(beta, uosm[i]); + } + return rosm; + } + + + // PARETO DISTRIBUTION + + // Pareto cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double paretoCDF(double alpha, double beta, double upperlimit){ + double y = 0.0D; + if(upperlimit>=beta)y = 1.0D - Math.pow(beta/upperlimit, alpha); + return y; + } + + // Pareto cumulative distribution function + // probability that a variate will assume a value less than the upperlimit + public static double paretoProb(double alpha, double beta, double upperlimit){ + double y = 0.0D; + if(upperlimit>=beta)y = 1.0D - Math.pow(beta/upperlimit, alpha); + return y; + } + + // Pareto cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double paretoCDF(double alpha, double beta, double lowerlimit, double upperlimit){ + double term1 = 0.0D, term2 = 0.0D; + if(lowerlimit>=beta)term1 = -Math.pow(beta/lowerlimit, alpha); + if(upperlimit>=beta)term2 = -Math.pow(beta/upperlimit, alpha); + return term2-term1; + } + + // Pareto cumulative distribution function + // probability that a variate will assume a value between the lower and the upper limits + public static double paretoProb(double alpha, double beta, double lowerlimit, double upperlimit){ + double term1 = 0.0D, term2 = 0.0D; + if(lowerlimit>=beta)term1 = -Math.pow(beta/lowerlimit, alpha); + if(upperlimit>=beta)term2 = -Math.pow(beta/upperlimit, alpha); + return term2-term1; + } + + // Pareto Inverse Cumulative Density Function + public static double paretoInverseCDF(double alpha, double beta, double prob){ + if(prob<0.0 || prob>1.0)throw new IllegalArgumentException("Entered cdf value, " + prob + ", must lie between 0 and 1 inclusive"); + double icdf = 0.0D; + + if(prob==0.0){ + icdf = beta; + } + else{ + if(prob==1.0){ + icdf = Double.POSITIVE_INFINITY; + } + else{ + icdf = beta/Math.pow((1.0 - prob), 1.0/alpha); + } + } + + return icdf; + } + + // Pareto Inverse Cumulative Density Function + public static double inverseParetoCDF(double alpha, double beta, double prob){ + return paretoInverseCDF(alpha, beta, prob); + } + + + // Pareto probability density function + public static double paretoPDF(double alpha, double beta, double x){ + double y = 0.0D; + if(x>=beta){ + y = alpha*Math.pow(beta, alpha)/Math.pow(x, alpha+1.0D); + } + return y; + } + + // Pareto probability density function + public static double pareto(double alpha, double beta, double x){ + double y = 0.0D; + if(x>=beta){ + y = alpha*Math.pow(beta, alpha)/Math.pow(x, alpha+1.0D); + } + return y; + } + + // Pareto mean + public static double paretoMean(double alpha, double beta){ + double y = Double.NaN; + if(alpha>1.0D)y = alpha*beta/(alpha-1); + return y; + } + + // Pareto standard deviation + public static double paretoStandardDeviation(double alpha, double beta){ + double y = Double.NaN; + if(alpha>1.0D)y = alpha*Fmath.square(beta)/(Fmath.square(alpha-1)*(alpha-2)); + return y; + } + + // Pareto standard deviation + public static double paretoStandDev(double alpha, double beta){ + double y = Double.NaN; + if(alpha>1.0D)y = alpha*Fmath.square(beta)/(Fmath.square(alpha-1)*(alpha-2)); + return y; + } + + // Pareto mode + public static double paretoMode(double beta){ + return beta; + } + + // Returns an array of Pareto random deviates - clock seed + public static double[] paretoRand(double alpha, double beta, int n){ + double[] ran = new double[n]; + Random rr = new Random(); + for(int i=0; i<n; i++){ + ran[i] = Math.pow(1.0D-rr.nextDouble(), -1.0D/alpha)*beta; + } + return ran; + } + + // Returns an array of Pareto random deviates - user supplied seed + public static double[] paretoRand(double alpha, double beta, int n, long seed){ + double[] ran = new double[n]; + Random rr = new Random(seed); + for(int i=0; i<n; i++){ + ran[i] = Math.pow(1.0D-rr.nextDouble(), -1.0D/alpha)*beta; + } + return ran; + } + + // Pareto order statistic medians (n points) + public static double[] paretoOrderStatisticMedians(double alpha, double beta, int n){ + double nn = (double)n; + double[] posm = new double[n]; + double[] uosm = uniformOrderStatisticMedians(n); + for(int i=0; i<n; i++){ + posm[i] = Stat.inverseParetoCDF(alpha, beta, uosm[i]); + } + return posm; + } + + + // FITTING DATA TO ABOVE DISTRIBUTIONS + + // Fit a data set to one, several or all of the above distributions (instance) + public void fitOneOrSeveralDistributions(){ + double[] dd = this.getArray_as_double(); + Regression.fitOneOrSeveralDistributions(dd); + } + + // Fit a data set to one, several or all of the above distributions (static) + public static void fitOneOrSeveralDistributions(double[] array){ + Regression.fitOneOrSeveralDistributions(array); + } + + + // OUTLIER TESTING (STATIC) + + // Anscombe test for a upper outlier - output as Vector + public static Vector<Object> upperOutliersAnscombeAsVector(double[] values, double constant){ + ArrayList<Object> res = Stat.upperOutliersAnscombeAsArrayList(values, constant); + Vector<Object> ret = null; + if(res!=null){ + int n = res.size(); + ret = new Vector<Object>(n); + for(int i=0; i<n; i++)ret.add(res.get(i)); + } + return ret; + } + + + // Anscombe test for a upper outlier as Vector + public static Vector<Object> upperOutliersAnscombe(double[] values, double constant){ + return upperOutliersAnscombeAsVector(values, constant); + } + + + // Anscombe test for a upper outlier - output as ArrayList + public static ArrayList<Object> upperOutliersAnscombeAsArrayList(double[] values, double constant){ + + Stat am = new Stat(values); + double[] copy0 = am.getArray_as_double(); + double[] copy1 = am.getArray_as_double(); + int nValues = values.length; + int nValues0 = nValues; + ArrayList<Object> outers = new ArrayList<Object>(); + int nOutliers = 0; + boolean test = true; + + while(test){ + double mean = am.mean_as_double(); + double standDev = am.standardDeviation_as_double(); + double max = am.getMaximum_as_double(); + int maxIndex = am.getMaximumIndex(); + double statistic = (max - mean)/standDev; + if(statistic>constant){ + outers.add(new Double(max)); + outers.add(new Integer(maxIndex)); + nOutliers++; + copy1 = new double[nValues-1]; + for(int i=maxIndex; i<nValues-1; i++)copy1[i] = copy0[i+1]; + + nValues--; + am = new Stat(copy1.clone()); + } + else{ + test=false; + } + } + + double[] outliers = null; + int[] outIndices = null; + + if(nOutliers>0){ + outliers = new double[nOutliers]; + outIndices = new int[nOutliers]; + for(int i=0; i<nOutliers; i++){ + outliers[i] = ((Double)outers.get(2*i)).doubleValue(); + outIndices[i] = ((Integer)outers.get(2*i+1)).intValue(); + } + } + + ArrayList<Object> ret = new ArrayList<Object>(4); + ret.add(new Integer(nOutliers)); + ret.add(outliers); + ret.add(outIndices); + ret.add(copy1); + return ret; + } + + // Anscombe test for a upper outlier - output as Vector + public static Vector<Object> upperOutliersAnscombeAsVector(BigDecimal[] values, BigDecimal constant){ + ArrayList<Object> res = Stat.upperOutliersAnscombeAsArrayList(values, constant); + Vector<Object> ret = null; + if(res!=null){ + int n = res.size(); + ret = new Vector<Object>(n); + for(int i=0; i<n; i++)ret.add(res.get(i)); + } + return ret; + } + + + // Anscombe test for a upper outlier as Vector + public static Vector<Object> upperOutliersAnscombe(BigDecimal[] values, BigDecimal constant){ + return upperOutliersAnscombeAsVector(values, constant); + } + + + // Anscombe test for a upper outlier - output as ArrayList + public static ArrayList<Object> upperOutliersAnscombeAsArrayList(BigDecimal[] values, BigDecimal constant){ + + Stat am = new Stat(values); + BigDecimal[] copy0 = am.getArray_as_BigDecimal(); + BigDecimal[] copy1 = am.getArray_as_BigDecimal(); + int nValues = values.length; + int nValues0 = nValues; + ArrayList<Object> outers = new ArrayList<Object>(); + int nOutliers = 0; + boolean test = true; + while(test){ + BigDecimal mean = am.mean_as_BigDecimal(); + BigDecimal variance = am.variance_as_BigDecimal(); + BigDecimal max = am.getMaximum_as_BigDecimal(); + int maxIndex = am.getMaximumIndex(); + BigDecimal statistic = (max.subtract(mean)).divide(variance, BigDecimal.ROUND_HALF_UP); + if(statistic.compareTo(constant.multiply(constant))==1){ + outers.add(max); + outers.add(new Integer(maxIndex)); + nOutliers++; + copy1 = new BigDecimal[nValues-1]; + for(int i=maxIndex; i<nValues-1; i++)copy1[i] = copy0[i+1]; + + nValues--; + am = new Stat(copy1.clone()); + } + else{ + mean = null; + variance = null; + statistic = null; + copy0 = null; + test=false; + } + } + + BigDecimal[] outliers = null; + int[] outIndices = null; + + if(nOutliers>0){ + outliers = new BigDecimal[nOutliers]; + outIndices = new int[nOutliers]; + for(int i=0; i<nOutliers; i++){ + outliers[i] = ((BigDecimal)outers.get(2*i)); + outIndices[i] = ((Integer)outers.get(2*i+1)).intValue(); + } + } + + ArrayList<Object> ret = new ArrayList<Object>(4); + ret.add(new Integer(nOutliers)); + ret.add(outliers); + ret.add(outIndices); + ret.add(copy1); + return ret; + } + + + // Anscombe test for a upper outlier - output as Vector + public static Vector<Object> upperOutliersAnscombeAsVector(BigInteger[] values, BigInteger constant){ + ArrayList<Object> res = Stat.upperOutliersAnscombeAsArrayList(values, constant); + Vector<Object> ret = null; + if(res!=null){ + int n = res.size(); + ret = new Vector<Object>(n); + for(int i=0; i<n; i++)ret.add(res.get(i)); + } + return ret; + } + + + // Anscombe test for a upper outlier as Vector + public static Vector<Object> upperOutliersAnscombe(BigInteger[] values, BigInteger constant){ + return upperOutliersAnscombeAsVector(values, constant); + } + + + // Anscombe test for a upper outlier - output as ArrayList + public static ArrayList<Object> upperOutliersAnscombeAsArrayList(BigInteger[] values, BigInteger constant){ + ArrayMaths am = new ArrayMaths(values); + BigDecimal[] bd = am.getArray_as_BigDecimal(); + BigDecimal cd = new BigDecimal(constant); + return Stat.upperOutliersAnscombeAsArrayList(bd, cd); + } + + + // Anscombe test for a lower outlier - output as Vector + public static Vector<Object> lowerOutliersAnscombeAsVector(double[] values, double constant){ + ArrayList<Object> res = Stat.lowerOutliersAnscombeAsArrayList(values, constant); + Vector<Object> ret = null; + if(res!=null){ + int n = res.size(); + ret = new Vector<Object>(n); + for(int i=0; i<n; i++)ret.add(res.get(i)); + } + return ret; + } + + + // Anscombe test for a lower outlier as Vector + public static Vector<Object> lowerOutliersAnscombe(double[] values, double constant){ + return upperOutliersAnscombeAsVector(values, constant); + } + + // Anscombe test for a lower outlier + public static ArrayList<Object> lowerOutliersAnscombeAsArrayList(double[] values, double constant){ + + Stat am = new Stat(values); + double[] copy0 = am.getArray_as_double(); + double[] copy1 = am.getArray_as_double(); + int nValues = values.length; + int nValues0 = nValues; + ArrayList<Object> outers = new ArrayList<Object>(); + int nOutliers = 0; + boolean test = true; + + while(test){ + double mean = am.mean_as_double(); + double standDev = am.standardDeviation_as_double(); + double min = am.getMinimum_as_double(); + int minIndex = am.getMinimumIndex(); + double statistic = (mean - min)/standDev; + if(statistic>constant){ + outers.add(new Double(min)); + outers.add(new Integer(minIndex)); + nOutliers++; + copy1 = new double[nValues-1]; + for(int i=minIndex; i<nValues-1; i++)copy1[i] = copy0[i+1]; + + nValues--; + am = new Stat(copy1.clone()); + } + else{ + test=false; + } + } + + double[] outliers = null; + int[] outIndices = null; + + if(nOutliers>0){ + outliers = new double[nOutliers]; + outIndices = new int[nOutliers]; + for(int i=0; i<nOutliers; i++){ + outliers[i] = ((Double)outers.get(2*i)).doubleValue(); + outIndices[i] = ((Integer)outers.get(2*i+1)).intValue(); + } + } + + ArrayList<Object> ret = new ArrayList<Object>(); + ret.add(new Integer(nOutliers)); + ret.add(outliers); + ret.add(outIndices); + ret.add(copy1); + return ret; + } + + // Anscombe test for a lower outlier - output as Vector + public static Vector<Object> lowerOutliersAnscombeAsVector(BigDecimal[] values, BigDecimal constant){ + ArrayList<Object> res = Stat.lowerOutliersAnscombeAsArrayList(values, constant); + Vector<Object> ret = null; + if(res!=null){ + int n = res.size(); + ret = new Vector<Object>(n); + for(int i=0; i<n; i++)ret.add(res.get(i)); + } + return ret; + } + + // Anscombe test for a lower outlier as Vector + public static Vector<Object> lowerOutliersAnscombe(BigDecimal[] values, BigDecimal constant){ + return upperOutliersAnscombeAsVector(values, constant); + } + + // Anscombe test for a lower outlier + public static ArrayList<Object> lowerOutliersAnscombeAsArrayList(BigDecimal[] values, BigDecimal constant){ + + Stat am = new Stat(values); + BigDecimal[] copy0 = am.getArray_as_BigDecimal(); + BigDecimal[] copy1 = am.getArray_as_BigDecimal(); + int nValues = values.length; + int nValues0 = nValues; + ArrayList<Object> outers = new ArrayList<Object>(); + int nOutliers = 0; + boolean test = true; + while(test){ + BigDecimal mean = am.mean_as_BigDecimal(); + BigDecimal variance = am.variance_as_BigDecimal(); + BigDecimal min = am.getMinimum_as_BigDecimal(); + int minIndex = am.getMinimumIndex(); + BigDecimal statistic = (mean.subtract(min)).divide(variance, BigDecimal.ROUND_HALF_UP); + if(statistic.compareTo(constant.multiply(constant))==1){ + outers.add(min); + outers.add(new Integer(minIndex)); + nOutliers++; + copy1 = new BigDecimal[nValues-1]; + for(int i=minIndex; i<nValues-1; i++)copy1[i] = copy0[i+1]; + + nValues--; + am = new Stat(copy1.clone()); + } + else{ + mean = null; + variance = null; + statistic = null; + copy0 = null; + test=false; + } + } + + BigDecimal[] outliers = null; + int[] outIndices = null; + + if(nOutliers>0){ + outliers = new BigDecimal[nOutliers]; + outIndices = new int[nOutliers]; + for(int i=0; i<nOutliers; i++){ + outliers[i] = ((BigDecimal)outers.get(2*i)); + outIndices[i] = ((Integer)outers.get(2*i+1)).intValue(); + } + } + + ArrayList<Object> ret = new ArrayList<Object>(); + ret.add(new Integer(nOutliers)); + ret.add(outliers); + ret.add(outIndices); + ret.add(copy1); + return ret; + } + + + // Anscombe test for a lower outlier - output as Vector + public static Vector<Object> lowerOutliersAnscombeAsVector(BigInteger[] values, BigInteger constant){ + ArrayList<Object> res = Stat.lowerOutliersAnscombeAsArrayList(values, constant); + Vector<Object> ret = null; + if(res!=null){ + int n = res.size(); + ret = new Vector<Object>(n); + for(int i=0; i<n; i++)ret.add(res.get(i)); + } + return ret; + } + + // Anscombe test for a lower outlier as Vector + public static Vector<Object> lowerOutliersAnscombe(BigInteger[] values, BigInteger constant){ + return upperOutliersAnscombeAsVector(values, constant); + } + + // Anscombe test for a lower outlier + public static ArrayList<Object> lowerOutliersAnscombeAsArrayList(BigInteger[] values, BigInteger constant){ + ArrayMaths am = new ArrayMaths(values); + BigDecimal[] bd = am.getArray_as_BigDecimal(); + BigDecimal cd = new BigDecimal(constant); + return Stat.lowerOutliersAnscombeAsArrayList(bd, cd); + } + + + + + + // METHODS OVERRIDING ArrayMaths METHODS + // DEEP COPY + // Copy to a new instance of Stat + public Stat copy(){ + + Stat am = new Stat(); + + if(this.amWeights==null){ + am.amWeights = null; + } + else{ + am.amWeights = this.amWeights; + } + am.weightsSupplied = this.weightsSupplied; + am.upperOutlierDetails = new ArrayList<Object>(); + if(this.upperOutlierDetails.size()!=0){ + Integer hold0 = (Integer)this.upperOutlierDetails.get(0); + am.upperOutlierDetails.add(hold0); + am.upperOutlierDetails.add(this.upperOutlierDetails.get(1)); + int[] hold2 = (int[])this.upperOutlierDetails.get(2); + am.upperOutlierDetails.add(hold2); + am.upperOutlierDetails.add(this.upperOutlierDetails.get(3)); + } + am.upperDone = this.upperDone; + am.lowerOutlierDetails = new ArrayList<Object>(); + if(this.lowerOutlierDetails.size()!=0){ + Integer hold0 = (Integer)this.lowerOutlierDetails.get(0); + am.lowerOutlierDetails.add(hold0); + am.lowerOutlierDetails.add(this.lowerOutlierDetails.get(1)); + int[] hold2 = (int[])this.lowerOutlierDetails.get(2); + am.lowerOutlierDetails.add(hold2); + am.lowerOutlierDetails.add(this.lowerOutlierDetails.get(3)); + } + am.lowerDone = this.lowerDone; + + am.length = this.length; + am.maxIndex = this.maxIndex; + am.minIndex = this.minIndex; + am.sumDone = this.sumDone; + am.productDone = this.productDone; + am.sumlongToDouble = this.sumlongToDouble; + am.productlongToDouble = this.productlongToDouble; + am.type = this.type; + if(this.originalTypes==null){ + am.originalTypes = null; + } + else{ + am.originalTypes = this.originalTypes.clone(); + } + if(this.sortedIndices==null){ + am.sortedIndices = null; + } + else{ + am.sortedIndices = this.sortedIndices.clone(); + } + am.suppressMessages = this.suppressMessages; + am.minmax = new ArrayList<Object>(); + if(this.minmax.size()!=0){ + switch(this.type){ + case 0: + case 1: double dd = ((Double)this.minmax.get(0)).doubleValue(); + am.minmax.add(new Double(dd)); + dd = ((Double)this.minmax.get(1)).doubleValue(); + am.minmax.add(new Double(dd)); + break; + case 4: + case 5: long ll= ((Long)this.minmax.get(0)).longValue(); + am.minmax.add(new Double(ll)); + ll = ((Long)this.minmax.get(1)).longValue(); + am.minmax.add(new Long(ll)); + break; + case 2: + case 3: float ff = ((Float)this.minmax.get(0)).floatValue(); + am.minmax.add(new Double(ff)); + ff = ((Float)this.minmax.get(1)).floatValue(); + am.minmax.add(new Double(ff)); + break; + case 6: + case 7: int ii = ((Integer)this.minmax.get(0)).intValue(); + am.minmax.add(new Integer(ii)); + ii = ((Double)this.minmax.get(1)).intValue(); + am.minmax.add(new Integer(ii)); + break; + case 8: + case 9: short ss = ((Short)this.minmax.get(0)).shortValue(); + am.minmax.add(new Short(ss)); + ss = ((Double)this.minmax.get(1)).shortValue(); + am.minmax.add(new Short((ss))); + break; + case 10: + case 11: byte bb = ((Byte)this.minmax.get(0)).byteValue(); + am.minmax.add(new Byte(bb)); + ss = ((Byte)this.minmax.get(1)).byteValue(); + am.minmax.add(new Byte((bb))); + break; + case 12: BigDecimal bd = (BigDecimal)this.minmax.get(0); + am.minmax.add(bd); + bd = (BigDecimal)this.minmax.get(1); + am.minmax.add(bd); + bd = null; + break; + case 13: BigInteger bi = (BigInteger)this.minmax.get(0); + am.minmax.add(bi); + bi = (BigInteger)this.minmax.get(1); + am.minmax.add(bi); + bi = null; + break; + case 16: + case 17: int iii = ((Integer)this.minmax.get(0)).intValue(); + am.minmax.add(new Integer(iii)); + iii = ((Double)this.minmax.get(1)).intValue(); + am.minmax.add(new Integer(iii)); + break; + } + } + + am.summ = new ArrayList<Object>(); + if(this.summ.size()!=0){ + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: double dd = ((Double)summ.get(0)).doubleValue(); + am.summ.add(new Double(dd)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + double dd2 = ((Double)summ.get(0)).doubleValue(); + am.summ.add(new Double(dd2)); + } + else{ + long ll = ((Long)summ.get(0)).longValue(); + am.summ.add(new Long(ll)); + } + break; + case 12: BigDecimal bd = (BigDecimal)summ.get(0); + am.summ.add(bd); + break; + case 13: BigInteger bi = (BigInteger)summ.get(0); + am.summ.add(bi); + break; + case 14: Complex cc = (Complex)summ.get(0); + am.summ.add(cc); + break; + case 15: Phasor pp = (Phasor)summ.get(0); + am.summ.add(pp); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + + am.productt = new ArrayList<Object>(); + if(this.productt.size()!=0){ + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: double dd = ((Double)productt.get(0)).doubleValue(); + am.productt.add(new Double(dd)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + double dd2 = ((Double)productt.get(0)).doubleValue(); + am.productt.add(new Double(dd2)); + } + else{ + long ll = ((Long)productt.get(0)).longValue(); + am.productt.add(new Long(ll)); + } + break; + case 12: BigDecimal bd = (BigDecimal)productt.get(0); + am.productt.add(bd); + break; + case 13: BigInteger bi = (BigInteger)productt.get(0); + am.productt.add(bi); + break; + case 14: Complex cc = (Complex)productt.get(0); + am.productt.add(cc); + break; + case 15: Phasor pp = (Phasor)productt.get(0); + am.productt.add(pp); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + + + switch(this.type){ + case 0: + case 1: double[] dd = this.getArray_as_double().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i])); + break; + case 2: + case 3: float[] ff = this.getArray_as_float().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Float(ff[i])); + break; + case 4: + case 5: long[] ll = this.getArray_as_long().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i])); + break; + case 6: + case 7: int[] ii = this.getArray_as_int().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Integer(ii[i])); + break; + case 8: + case 9: short[] ss = this.getArray_as_short().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Short(ss[i])); + break; + case 10: + case 11: byte[] bb = this.getArray_as_byte().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Byte(bb[i])); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal().clone(); + for(int i=0; i<this.length; i++)am.array.add(bd[i]); + break; + case 13: BigInteger[] bi = this.getArray_as_BigInteger().clone(); + for(int i=0; i<this.length; i++)am.array.add(bi[i]); + break; + case 14: Complex[] ccc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(ccc[i].copy()); + break; + case 15: Phasor[] ppp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(ppp[i].copy()); + break; + case 16: + case 17: char[] cc = this.getArray_as_char().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Character(cc[i])); + break; + case 18: String[] sss = this.getArray_as_String().clone(); + for(int i=0; i<this.length; i++)am.array.add(sss[i]); + break; + } + + return am; + } + + public Stat plus(double constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(float constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(long constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(int constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(short constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(byte constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(char constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(BigDecimal constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(BigInteger constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(Complex constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(Phasor constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(String constant){ + return super.plus(constant).toStat(); + } + + + public Stat plus(Double constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(Float constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(Long constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(Integer constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(Short constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(Byte constant){ + return super.plus(constant).toStat(); + } + + + public Stat plus(Character constant){ + return super.plus(constant).toStat(); + } + + public Stat plus(Stat arrays){ + return super.plus(arrays).toStat(); + } + + public Stat plus(ArrayMaths arraym){ + return super.plus(arraym).toStat(); + } + + public Stat plus(ArrayList<Object> arrayl){ + return super.plus(arrayl).toStat(); + } + + public Stat plus(Vector<Object> list){ + return super.plus(list).toStat(); + } + + public Stat plus(double[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(float[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(long[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(int[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(short[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(byte[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(char[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(BigDecimal[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(BigInteger[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(Complex[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(Phasor[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(String[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(Double[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(Float[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(Long[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(Integer[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(Short[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(Byte[] array){ + return super.plus(array).toStat(); + } + + public Stat plus(Character[] array){ + return super.plus(array).toStat(); + } + + public Stat minus(double constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(float constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(long constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(int constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(short constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(byte constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(char constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(BigDecimal constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(BigInteger constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(Complex constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(Phasor constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(Double constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(Float constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(Long constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(Integer constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(Short constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(Byte constant){ + return super.minus(constant).toStat(); + } + + + public Stat minus(Character constant){ + return super.minus(constant).toStat(); + } + + public Stat minus(Stat arrays){ + return super.minus(arrays).toStat(); + } + + public Stat minus(ArrayMaths arraym){ + return super.minus(arraym).toStat(); + } + + public Stat minus(Vector<Object> vec){ + return super.minus(vec).toStat(); + } + + public Stat minus(ArrayList<Object> list){ + return super.minus(list).toStat(); + } + + public Stat minus(double[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(float[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(long[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(int[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(short[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(byte[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(BigDecimal[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(BigInteger[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(Complex[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(Phasor[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(Double[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(Float[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(Long[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(Integer[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(Short[] array){ + return super.minus(array).toStat(); + } + + public Stat minus(Byte[] array){ + return super.minus(array).toStat(); + } + + public Stat times(double constant){ + return super.times(constant).toStat(); + } + + public Stat times(float constant){ + return super.times(constant).toStat(); + } + + public Stat times(long constant){ + return super.times(constant).toStat(); + } + + public Stat times(int constant){ + return super.times(constant).toStat(); + } + + public Stat times(short constant){ + return super.times(constant).toStat(); + } + + public Stat times(byte constant){ + return super.times(constant).toStat(); + } + + public Stat times(BigDecimal constant){ + return super.times(constant).toStat(); + } + + public Stat times(BigInteger constant){ + return super.times(constant).toStat(); + } + + public Stat times(Complex constant){ + return super.times(constant).toStat(); + } + + public Stat times(Phasor constant){ + return super.times(constant).toStat(); + } + + public Stat times(Double constant){ + return super.times(constant).toStat(); + } + + public Stat times(Float constant){ + return super.times(constant).toStat(); + } + + public Stat times(Long constant){ + return super.times(constant).toStat(); + } + + public Stat times(Integer constant){ + return super.times(constant).toStat(); + } + + public Stat times(Short constant){ + return super.times(constant).toStat(); + } + + public Stat times(Byte constant){ + return super.times(constant).toStat(); + } + + public Stat over(double constant){ + return super.over(constant).toStat(); + } + + public Stat over(float constant){ + return super.over(constant).toStat(); + } + + public Stat over(long constant){ + return super.over(constant).toStat(); + } + + public Stat over(int constant){ + return super.over(constant).toStat(); + } + + public Stat over(short constant){ + return super.over(constant).toStat(); + } + + public Stat over(byte constant){ + return super.over(constant).toStat(); + } + + public Stat over(BigDecimal constant){ + return super.over(constant).toStat(); + } + + public Stat over(BigInteger constant){ + return super.over(constant).toStat(); + } + + public Stat over(Complex constant){ + return super.over(constant).toStat(); + } + + public Stat over(Phasor constant){ + return super.over(constant).toStat(); + } + + public Stat over(Double constant){ + return super.over(constant).toStat(); + } + + public Stat over(Float constant){ + return super.over(constant).toStat(); + } + + public Stat over(Long constant){ + return super.over(constant).toStat(); + } + + public Stat over(Integer constant){ + return super.over(constant).toStat(); + } + + public Stat over(Short constant){ + return super.over(constant).toStat(); + } + + public Stat over(Byte constant){ + return super.over(constant).toStat(); + } + + + public Stat pow(double n){ + return super.pow(n).toStat(); + } + + public Stat pow(float n){ + return super.pow(n).toStat(); + } + + public Stat pow(long n){ + return super.pow(n).toStat(); + } + + public Stat pow(int n){ + return super.pow(n).toStat(); + } + + public Stat pow(short n){ + return super.pow(n).toStat(); + } + + public Stat pow(byte n){ + return super.pow(n).toStat(); + } + + public Stat pow(Double n){ + return super.pow(n).toStat(); + } + + public Stat pow(Float n){ + return super.pow(n).toStat(); + } + + public Stat pow(Long n){ + return super.pow(n).toStat(); + } + + public Stat pow(Integer n){ + return super.pow(n).toStat(); + } + + public Stat pow(Short n){ + return super.pow(n).toStat(); + } + + public Stat pow(Byte n){ + return super.pow(n).toStat(); + } + + public Stat pow(BigInteger n){ + return super.pow(n).toStat(); + } + + public Stat pow(BigDecimal n){ + return super.pow(n).toStat(); + } + + public Stat sqrt(){ + return super.sqrt().toStat(); + } + + public Stat oneOverSqrt(){ + return super.oneOverSqrt().toStat(); + } + + public Stat abs(){ + return super.abs().toStat(); + } + + public Stat log(){ + return super.log().toStat(); + } + + public Stat log2(){ + return super.log2().toStat(); + } + + public Stat log10(){ + return super.log10().toStat(); + } + + public Stat antilog10(){ + return super.antilog10().toStat(); + } + + public Stat xLog2x(){ + return super.xLog2x().toStat(); + } + + public Stat xLogEx(){ + return super.xLogEx().toStat(); + } + + public Stat xLog10x(){ + return super.xLog10x().toStat(); + } + + public Stat minusxLog2x(){ + return super.minusxLog2x().toStat(); + } + + public Stat minusxLogEx(){ + return super.minusxLogEx().toStat(); + } + + public Stat minusxLog10x(){ + return super.minusxLog10x().toStat(); + } + + public Stat exp(){ + return super.exp().toStat(); + } + + public Stat invert(){ + return super.invert().toStat(); + } + + public Stat negate(){ + return super.negate().toStat(); + } + + public Stat sort(){ + return super.sort().toStat(); + } + + public Stat sort(int[] indices){ + return super.sort(indices).toStat(); + } + + public Stat reverse(){ + return super.reverse().toStat(); + } + + public Stat concatenate(Stat xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(ArrayMaths xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(double[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(float[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(long[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(int[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(short[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(byte[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(char[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(Double[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(Float[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(Long[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(Integer[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(Short[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(Byte[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(Character[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(String[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(BigDecimal[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(BigInteger[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(Complex[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat concatenate(Phasor[] xx){ + return super.concatenate(xx).toStat(); + } + + public Stat truncate(int n){ + return super.truncate(n).toStat(); + } + + public Stat floor(){ + return super.floor().toStat(); + } + + public Stat ceil(){ + return super.ceil().toStat(); + } + + public Stat rint(){ + return super.rint().toStat(); + } + + public Stat randomize(){ + return super.randomize().toStat(); + } + + public Stat randomise(){ + return super.randomize().toStat(); + } + +} + +// CLASSES NEEDED BY METHODS IN THE ABOVE Stat CLASS + +// Class to evaluate the linear correlation coefficient probablity function +// Needed in calls to Integration.gaussQuad +class CorrCoeff implements IntegralFunction{ + + public double a; + + public double function(double x){ + double y = Math.pow((1.0D - x*x),a); + return y; + } +} + +// Class to evaluate the normal distribution function +class GaussianFunct implements RealRootFunction{ + + public double cfd = 0.0D; + public double mean = 0.0D; + public double sd = 0.0; + + public double function(double x){ + + double y = cfd - Stat.gaussianCDF(mean, sd, x); + + return y; + } +} + +// Class to evaluate the Student's t-function +class StudentTfunct implements RealRootFunction{ + public int nu = 0; + public double cfd = 0.0D; + + public double function(double x){ + + double y = cfd - Stat.studentTcdf(x, nu); + + return y; + } +} + +// Class to evaluate the Gamma distribution function +class GammaFunct implements RealRootFunction{ + public double mu = 0.0D; + public double beta = 0.0D; + public double gamma = 0.0D; + public double cfd = 0.0D; + + public double function(double x){ + + double y = cfd - Stat.gammaCDF(mu, beta, gamma, x); + + return y; + } +} + +// Class to evaluate the Beta distribution function +class BetaFunct implements RealRootFunction{ + public double alpha = 0.0D; + public double beta = 0.0D; + public double min = 0.0D; + public double max = 0.0D; + public double cfd = 0.0D; + + public double function(double x){ + + double y = cfd - Stat.betaCDF(min, max, alpha, beta, x); + + return y; + } +} + +// Class to evaluate the Erlang B equation +class ErlangBfunct implements RealRootFunction{ + + public double blockingProbability = 0.0D; + public double totalResources = 0.0D; + + public double function(double x){ + return blockingProbability - Stat.erlangBprobability(x, totalResources); + } +} + +// Class to evaluate the Erlang C equation +class ErlangCfunct implements RealRootFunction{ + + public double nonZeroDelayProbability = 0.0D; + public double totalResources = 0.0D; + + public double function(double x){ + return nonZeroDelayProbability - Stat.erlangCprobability(x, totalResources); + } +} + +// Class to evaluate the Engset probability equation +class EngsetProb implements RealRootFunction{ + + public double offeredTraffic = 0.0D; + public double totalResources = 0.0D; + public double numberOfSources = 0.0D; + + public double function(double x){ + double mTerm = offeredTraffic/(numberOfSources - offeredTraffic*(1.0D - x)); + double pNumer = Stat.logFactorial(numberOfSources-1) - Stat.logFactorial(totalResources) - Stat.logFactorial(numberOfSources-1-totalResources); + double pDenom = 0.0D; + double iDenom = 0.0D; + double iCount = 0.0D; + double pTerm = 0.0D; + + while(iCount<=totalResources){ + iDenom = Stat.logFactorial(numberOfSources-1) - Stat.logFactorial(iCount) - Stat.logFactorial(numberOfSources-1-iCount); + iDenom += (iCount-totalResources)*Math.log(mTerm); + pDenom += Math.exp(iDenom); + iCount += 1.0D; + } + pTerm = Math.exp(pNumer - Math.log(pDenom)); + + return x - pTerm; + } +} + + +// Class to evaluate the Engset load equation +class EngsetLoad implements RealRootFunction{ + + public double blockingProbability = 0.0D; + public double totalResources = 0.0D; + public double numberOfSources = 0.0D; + + + public double function(double x){ + return blockingProbability - Stat.engsetProbability(x, totalResources, numberOfSources); + } +} + +// Class to evaluate the chi-square distribution function +class ChiSquareFunct implements RealRootFunction{ + + public double cfd = 0.0D; + public int nu = 0; + + public double function(double x){ + + double y = cfd - Stat.chiSquareCDF(x, nu); + + return y; + } +} + +// Class to evaluate the F-distribution function +class FdistribtionFunct implements RealRootFunction{ + + public double cfd = 0.0D; + public int nu1 = 0; + public int nu2 = 0; + + public double function(double x){ + + double y = cfd - (1.0 - Stat.fCompCDF(x, nu1, nu2)); + // double y = cfd - Stat.fCompCDF(x, nu1, nu2); + + return y; + } +} + +// Class to evaluate the two parameter log-normal distribution function +class LogNormalTwoParFunct implements RealRootFunction{ + + public double cfd = 0.0D; + public double mu = 0.0D; + public double sigma = 0.0D; + + public double function(double x){ + + double y = cfd - Stat.logNormalCDF(mu, sigma, x); + + return y; + } +} + +// Class to evaluate inverse gamma function +class InverseGammaFunct implements RealRootFunction{ + + public double gamma = 0.0D; + + public double function(double x){ + + double y = gamma - Stat.gamma(x); + + return y; + } +} diff --git a/src/main/java/flanagan/circuits/CoaxialLine.java b/src/main/java/flanagan/circuits/CoaxialLine.java new file mode 100755 index 0000000000000000000000000000000000000000..74552e77a13679fd1f9e8ce794b52868cea15b9d --- /dev/null +++ b/src/main/java/flanagan/circuits/CoaxialLine.java @@ -0,0 +1,323 @@ +/* Class CoaxialLine +* +* Models a coaxial transmission line +* This is a subclass of the superclass TransmissionLine +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: July 2007 +* UPDATE: 7 April 2008 +* +* DOCUMENTATION: +* See Michael T Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/CoaxialLine.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/TransmissionLine.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2007 - 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.circuits; + +import flanagan.complex.Complex; + +public class CoaxialLine extends TransmissionLine{ + + private double innerRadius = -1.0D; // inner radius - coaxial centre to outer surface of inner conductor + private double outerRadius = -1.0D; // outer radius - coaxial centre to inner surface of outer conductor + private boolean radiiSet = false; // = true when both inner and outer radii entered + + private double relativePermittivity = 1.0D; // relative electrical permittivity of the material between the conductors + private double relativePermeability = 1.0D; // relative magnetic permeability of the material between the conductors + + + // CONSTRUCTOR + // default constructor + public CoaxialLine(){ + super.title = "Coaxial Line"; + } + + // user provided title + public CoaxialLine(String title){ + super.title = title; + } + + // RADII + // Set inner and outer radii + // inner: coaxial centre to outer surface of inner conductor + // outer: coaxial centre to inner surface of outer conductor + public void setRadii(double innerRadius, double outerRadius){ + if(innerRadius<=0.0D)throw new IllegalArgumentException("The inner radius, " + innerRadius + ", must be greater than zero"); + if(outerRadius<=0.0D)throw new IllegalArgumentException("The outer radius, " + outerRadius + ", must be greater than zero"); + if(innerRadius >= outerRadius)throw new IllegalArgumentException("The inner radius, " + innerRadius + ", must be less than the outer radius, " + outerRadius); + this.innerRadius = innerRadius; + this.outerRadius = outerRadius; + this.radiiSet = true; + this.calculateDistributedCapacitanceAndInductance(); + } + + // Set inner radius - coaxial centre to outer surface of inner conductor + public void setInnerRadius(double radius){ + if(radius<=0.0D)throw new IllegalArgumentException("The inner radius, " + radius + ", must be greater than zero"); + if(this.outerRadius!=-1.0D && this.outerRadius<=radius)throw new IllegalArgumentException("The inner radius, " + radius + ", must be less than the outer radius, " + this.outerRadius); + this.innerRadius = radius; + if(this.outerRadius!=-1.0)this.radiiSet = true; + if(this.radiiSet)this.calculateDistributedCapacitanceAndInductance(); + } + + // Set outer radius - coaxial centre to inner surface of outer conductor + public void setOuterRadius(double radius){ + if(radius<=0.0D)throw new IllegalArgumentException("The outer radius, " + radius + ", must be greater than zero"); + if(this.innerRadius!=-1.0D && this.innerRadius>=radius)throw new IllegalArgumentException("The outer radius, " + radius + ", must be greater than the inner radius, " + this.innerRadius); + this.outerRadius = radius; + if(this.innerRadius!=-1.0)this.radiiSet = true; + if(this.radiiSet)this.calculateDistributedCapacitanceAndInductance(); + } + + // PERMITTIVITY + // Set relative electrical permittivity of the material between the conductors + public void setRelativePermittivity(double epsilonR){ + this.relativePermittivity = epsilonR; + if(this.radiiSet)this.calculateDistributedCapacitanceAndInductance(); + } + + // PERMEABILTY + // Set relative magnetic permeability of the material between the conductors + public void setRelativePermeability(double muR){ + this.relativePermeability = muR; + if(this.radiiSet)this.calculateDistributedCapacitanceAndInductance(); + } + + // CALCULATE DISTRIBUTED PARAMETERS + private void calculateDistributedCapacitanceAndInductance(){ + super.distributedCapacitance = Impedance.coaxialCapacitance(1.0D, this.innerRadius, this.outerRadius, this.relativePermittivity); + super.distributedInductance = Impedance.coaxialInductance(1.0D, this.innerRadius, this.outerRadius, this.relativePermeability); + } + + // DEEP COPY + public CoaxialLine copy(){ + + if(this==null){ + return null; + } + else{ + CoaxialLine tl = new CoaxialLine(); + + tl.innerRadius = this.innerRadius; + tl.outerRadius = this.outerRadius; + tl.radiiSet = this.radiiSet; + tl.relativePermittivity = this.relativePermittivity; + tl.relativePermeability = this.relativePermeability; + + tl.title = this.title; + tl.distributedResistance = this.distributedResistance; + tl.distributedConductance = this.distributedConductance; + tl.distributedCapacitance = this.distributedCapacitance; + tl.distributedInductance = this.distributedInductance; + + tl.distributedImpedance = this.distributedImpedance.copy(); + tl.distributedAdmittance = this.distributedAdmittance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.lineLength = this.lineLength; + tl.segmentLength = this.segmentLength; + tl.frequency = this.frequency; + tl.segmentLength = this.segmentLength; + tl.omega = this.omega; + + tl.inputVoltage = this.inputVoltage.copy(); + tl.inputCurrent = this.inputCurrent.copy(); + tl.outputVoltage = this.outputVoltage.copy(); + tl.outputCurrent = this.outputCurrent.copy(); + + tl.idealWavelength = this.idealWavelength; + tl.generalWavelength = this.generalWavelength; + tl.lowLossWavelength = this.lowLossWavelength; + + tl.idealPhaseVelocity = this.idealPhaseVelocity; + tl.generalPhaseVelocity = this.generalPhaseVelocity; + tl.lowLossPhaseVelocity = this.lowLossPhaseVelocity; + + tl.idealGroupVelocity = this.idealGroupVelocity; + tl.generalGroupVelocity = this.generalGroupVelocity; + tl.lowLossGroupVelocity = this.lowLossGroupVelocity; + tl.delta = this.delta; + + tl.idealAttenuationConstant = this.idealAttenuationConstant; + tl.generalAttenuationConstant = this.generalAttenuationConstant; + tl.lowLossAttenuationConstant = this.lowLossAttenuationConstant; + + tl.idealPhaseConstant = this.idealPhaseConstant; + tl.generalPhaseConstant = this.generalPhaseConstant; + tl.lowLossPhaseConstant = this.lowLossPhaseConstant; + + tl.idealPropagationConstant = this.idealPropagationConstant.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.generalPropagationConstant = this.generalPropagationConstant.copy(); + tl.lowLossPropagationConstant = this.lowLossPropagationConstant.copy(); + tl.idealCharacteristicImpedance = this.idealCharacteristicImpedance.copy(); + tl.idealRealCharacteristicImpedance = this.idealRealCharacteristicImpedance; + + tl.generalCharacteristicImpedance = this.generalCharacteristicImpedance.copy(); + tl.lowLossCharacteristicImpedance = this.lowLossCharacteristicImpedance.copy(); + tl.idealInputImpedance = this.idealInputImpedance.copy(); + tl.generalInputImpedance = this.generalInputImpedance.copy(); + tl.lowLossInputImpedance = this.lowLossInputImpedance.copy(); + + tl.idealShortedLineImpedance = this.idealShortedLineImpedance.copy(); + tl.generalShortedLineImpedance = this.generalShortedLineImpedance.copy(); + tl.lowLossShortedLineImpedance = this.lowLossShortedLineImpedance.copy(); + + tl.idealOpenLineImpedance = this.idealOpenLineImpedance.copy(); + tl.generalOpenLineImpedance = this.generalOpenLineImpedance.copy(); + tl.lowLossOpenLineImpedance = this.lowLossOpenLineImpedance.copy(); + + tl.idealQuarterWaveLineImpedance = this.idealQuarterWaveLineImpedance.copy(); + tl.generalQuarterWaveLineImpedance = this.generalQuarterWaveLineImpedance.copy(); + tl.lowLossQuarterWaveLineImpedance = this.lowLossQuarterWaveLineImpedance.copy(); + + tl.idealHalfWaveLineImpedance = this.idealHalfWaveLineImpedance.copy(); + tl.generalHalfWaveLineImpedance = this.generalHalfWaveLineImpedance.copy(); + tl.lowLossHalfWaveLineImpedance = this.lowLossHalfWaveLineImpedance.copy(); + + tl.idealRefectionCoefficient = this.idealRefectionCoefficient.copy(); + tl.generalRefectionCoefficient = this.generalRefectionCoefficient.copy(); + tl.lowLossRefectionCoefficient = this.lowLossRefectionCoefficient.copy(); + + tl.idealStandingWaveRatio = this.idealStandingWaveRatio; + tl.generalStandingWaveRatio = this.generalStandingWaveRatio; + tl.lowLossStandingWaveRatio = this.lowLossStandingWaveRatio; + + tl.idealABCDmatrix = this.idealABCDmatrix.copy(); + tl.generalABCDmatrix = this.generalABCDmatrix.copy(); + tl.lowLossABCDmatrix = this.lowLossABCDmatrix.copy(); + + tl.numberOfPoints = this.numberOfPoints; + + return tl; + } + } + + + // Clone - overrides Java.Object method clone + public Object clone(){ + + Object ret = null; + + if(this!=null){ + + CoaxialLine tl = new CoaxialLine(); + + tl.innerRadius = this.innerRadius; + tl.outerRadius = this.outerRadius; + tl.radiiSet = this.radiiSet; + tl.relativePermittivity = this.relativePermittivity; + tl.relativePermeability = this.relativePermeability; + + tl.title = this.title; + tl.distributedResistance = this.distributedResistance; + tl.distributedConductance = this.distributedConductance; + tl.distributedCapacitance = this.distributedCapacitance; + tl.distributedInductance = this.distributedInductance; + + tl.distributedImpedance = this.distributedImpedance.copy(); + tl.distributedAdmittance = this.distributedAdmittance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.lineLength = this.lineLength; + tl.segmentLength = this.segmentLength; + tl.frequency = this.frequency; + tl.segmentLength = this.segmentLength; + tl.omega = this.omega; + + tl.inputVoltage = this.inputVoltage.copy(); + tl.inputCurrent = this.inputCurrent.copy(); + tl.outputVoltage = this.outputVoltage.copy(); + tl.outputCurrent = this.outputCurrent.copy(); + + tl.idealWavelength = this.idealWavelength; + tl.generalWavelength = this.generalWavelength; + tl.lowLossWavelength = this.lowLossWavelength; + + tl.idealPhaseVelocity = this.idealPhaseVelocity; + tl.generalPhaseVelocity = this.generalPhaseVelocity; + tl.lowLossPhaseVelocity = this.lowLossPhaseVelocity; + + tl.idealGroupVelocity = this.idealGroupVelocity; + tl.generalGroupVelocity = this.generalGroupVelocity; + tl.lowLossGroupVelocity = this.lowLossGroupVelocity; + tl.delta = this.delta; + + tl.idealAttenuationConstant = this.idealAttenuationConstant; + tl.generalAttenuationConstant = this.generalAttenuationConstant; + tl.lowLossAttenuationConstant = this.lowLossAttenuationConstant; + + tl.idealPhaseConstant = this.idealPhaseConstant; + tl.generalPhaseConstant = this.generalPhaseConstant; + tl.lowLossPhaseConstant = this.lowLossPhaseConstant; + + tl.idealPropagationConstant = this.idealPropagationConstant.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.generalPropagationConstant = this.generalPropagationConstant.copy(); + tl.lowLossPropagationConstant = this.lowLossPropagationConstant.copy(); + tl.idealCharacteristicImpedance = this.idealCharacteristicImpedance.copy(); + tl.idealRealCharacteristicImpedance = this.idealRealCharacteristicImpedance; + + tl.generalCharacteristicImpedance = this.generalCharacteristicImpedance.copy(); + tl.lowLossCharacteristicImpedance = this.lowLossCharacteristicImpedance.copy(); + tl.idealInputImpedance = this.idealInputImpedance.copy(); + tl.generalInputImpedance = this.generalInputImpedance.copy(); + tl.lowLossInputImpedance = this.lowLossInputImpedance.copy(); + + tl.idealShortedLineImpedance = this.idealShortedLineImpedance.copy(); + tl.generalShortedLineImpedance = this.generalShortedLineImpedance.copy(); + tl.lowLossShortedLineImpedance = this.lowLossShortedLineImpedance.copy(); + + tl.idealOpenLineImpedance = this.idealOpenLineImpedance.copy(); + tl.generalOpenLineImpedance = this.generalOpenLineImpedance.copy(); + tl.lowLossOpenLineImpedance = this.lowLossOpenLineImpedance.copy(); + + tl.idealQuarterWaveLineImpedance = this.idealQuarterWaveLineImpedance.copy(); + tl.generalQuarterWaveLineImpedance = this.generalQuarterWaveLineImpedance.copy(); + tl.lowLossQuarterWaveLineImpedance = this.lowLossQuarterWaveLineImpedance.copy(); + + tl.idealHalfWaveLineImpedance = this.idealHalfWaveLineImpedance.copy(); + tl.generalHalfWaveLineImpedance = this.generalHalfWaveLineImpedance.copy(); + tl.lowLossHalfWaveLineImpedance = this.lowLossHalfWaveLineImpedance.copy(); + + tl.idealRefectionCoefficient = this.idealRefectionCoefficient.copy(); + tl.generalRefectionCoefficient = this.generalRefectionCoefficient.copy(); + tl.lowLossRefectionCoefficient = this.lowLossRefectionCoefficient.copy(); + + tl.idealStandingWaveRatio = this.idealStandingWaveRatio; + tl.generalStandingWaveRatio = this.generalStandingWaveRatio; + tl.lowLossStandingWaveRatio = this.lowLossStandingWaveRatio; + + tl.idealABCDmatrix = this.idealABCDmatrix.copy(); + tl.generalABCDmatrix = this.generalABCDmatrix.copy(); + tl.lowLossABCDmatrix = this.lowLossABCDmatrix.copy(); + + tl.numberOfPoints = this.numberOfPoints; + + ret = (Object)tl; + } + return ret; + } +} diff --git a/src/main/java/flanagan/circuits/ImpedSpecModel.java b/src/main/java/flanagan/circuits/ImpedSpecModel.java new file mode 100755 index 0000000000000000000000000000000000000000..76adcc754b94fcf238e559b258f47a579ada86cf --- /dev/null +++ b/src/main/java/flanagan/circuits/ImpedSpecModel.java @@ -0,0 +1,36 @@ +/* Interface ImpedSpecModel +* +* Needed for user supplied model circuits in the classes +* ImpedSpecSimulation and ImpedSpecRegression +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: May 2007 (Derived from impedance spectroscopy programs, 2004 - 2007) +* +* DOCUMENTATION: +* See Michael T Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ImpedSpecSimulation.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ImpedSpecRegression.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) May 2007 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +****************************************************************************************/ + +package flanagan.circuits; + +import flanagan.complex.Complex; + +public interface ImpedSpecModel{ + Complex modelImpedance(double[] parameters, double omega); +} \ No newline at end of file diff --git a/src/main/java/flanagan/circuits/ImpedSpecRegression.java b/src/main/java/flanagan/circuits/ImpedSpecRegression.java new file mode 100755 index 0000000000000000000000000000000000000000..a9d15322e79054e92a00cd2dba355cffb9bd3d79 --- /dev/null +++ b/src/main/java/flanagan/circuits/ImpedSpecRegression.java @@ -0,0 +1,2435 @@ +/* Class ImpedSpecRegression +* +* Non-linear regression procedures for fitting impedance +* spectroscopy and electrochemical impedance spectroscopy +* data to user supplied circuit or one of a range of precompiled +* circuit models. +* +* User supplied circuit models require the interface ImpedSpecModel +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 9 June 2007 (Derived from impedance spectroscopy programs, 2004 - 2007) +* UPDATE: 16 October 2007, 5 July 2008 +* +* DOCUMENTATION: +* See Michael T Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* http://www.ee.ucl.ac.uk/~mflanaga/java/ImpedSpecRegression.html +* +* Copyright (c) June 2007 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +****************************************************************************************/ + +package flanagan.circuits; + +import flanagan.io.*; +import flanagan.complex.Complex; +import flanagan.complex.ComplexErrorProp; +import flanagan.analysis.ErrorProp; +import flanagan.analysis.Regression; +import flanagan.analysis.RegressionFunction2; +import flanagan.analysis.Stat; +import flanagan.math.Fmath; +import flanagan.plot.*; + +import java.lang.reflect.Array; +import java.text.*; +import java.util.*; +import java.lang.Object; + + +public class ImpedSpecRegression extends Regression{ + + private String regressionTitle = null; // Title for output graphs and text file + private boolean fileType = false; // = true if 'n' number to be added to file name + + private Complex appliedVoltage = null; // magnitude of the applied voltage as complex + private boolean appliedVoltageSet = false; // = true when applied voltage entered + private Complex appliedVoltageError = null; // error of the applied voltage as complex + private boolean voltageErrorSet = false; // = true when applied voltage error entered + + private Complex referenceImpedance = null; // reference impedance + private boolean referenceSet = false; // = true when reference impedance entered + + private double[] frequencies = null; // frequencies [Hz] + private double[] omegas = null; // radial frequencies + private double[] log10frequencies = null; // log10[frequencies/Hz] + private double[] log10omegas = null; // log10[radial frequencies] + private int numberOfFrequencies = 0; // number of points in the simulation + private boolean frequenciesSet = false; // = true when frequencies entered + + private Complex[] voltages = null; // voltages + private Complex[] voltageWeights = null; // voltage weights + private double[] voltageMagnitudes = null; // magnitude of the voltages + private double[] voltageMagnitudeWeights = null; // voltage magnitude weights + private double[] voltagePhasesRad = null; // voltage phases [radians]of the voltages + private double[] voltagePhaseWeightsRad = null; // voltage phase weights [radians] + private double[] voltagePhasesDeg = null; // voltage phases [degrees]of the voltages + private double[] voltagePhaseWeightsDeg = null; // voltage phase weights [degrees] + private double[] realV = null; // real part of the voltage + private double[] realVweights = null; // real part of the voltage - weights + private double[] imagV = null; // imaginary part of the voltages + private double[] imagVweights = null; // imaginary part of the voltage - weights + + private boolean weightsSet = true; // = false if no weights provided + + private int dataEnteredTypePointer = -1; // = 0; real and imag voltage + // = 1: complex voltage + // = 2: voltage magnitude and radians + // = 3: voltage magnitude and degreees + // = 4; real and imag impedance + // = 5: complex mpedance + // = 6: mpedance magnitude and radians + // = 7: mpedance magnitude and degreees + // Entered data type + private String[] dataEnteredType = {"Complex voltage (as real and imaginary parts)", "Complex voltage (as Complex)", "Voltage Magnitude and phase (in radians)", "Voltage Magnitude and phase (in degrees)", "Complex impedance (as real and imaginary parts)", "Complex impedance (as Complex)", "Magnitude and phase (in radians)", "Magnitude and phase (in degrees)"}; + private boolean voltageOrImpedance = true; // = true: data entered as test circuit voltages + // = false: data entered as test circuit impedances + + private Complex[] impedances = null; // model impedances + private Complex[] impedanceWeights = null; // model impedance weights + private double[] impedanceMagnitudes = null; // magnitude of the impedances + private double[] impedanceMagnitudeWeights = null; // impedance magnitude weights + private double[] impedancePhasesRad = null; // impedance phases [radians]of the impedances + private double[] impedancePhaseWeightsRad = null; // impedance phase weights [radians] + private double[] impedancePhasesDeg = null; // impedance phases [degrees]of the impedances + private double[] impedancePhaseWeightsDeg = null; // impedance phase weights [degrees] + private double[] realZ = null; // real part of the model impedance + private double[] realZweights = null; // real part of the model impedance - weights + private double[] imagZ = null; // imaginary part of the model impedance + private double[] imagZweights = null; // imaginary part of the model impedance - weights + private boolean impedancesSet = false; // = true when impedances calculated + + + private double[] xRegression = null; // regression x-axis data + private double[][] yRegression = null; // regression y-axis data + private double[][] wRegression = null; // regression weights + + private int modelNumber = 0; // model number + private int numberOfParameters = 0; // number of model parameters + private String[] parameterSymbols = null; // model parameter symbols + private boolean modelSet = false; // = true when a model number is entered + private boolean estimatesNeeded = false; // = true when a no estimates are to be entered and they are yet to be calculated + + private boolean supressDefaultConstraints = false; // = true when in-built constraints on parameters supressed + private boolean supressAddedConstraints = false; // = true when added constraints on parameters supressed + private boolean supressAllConstraints = false; // = true when all constraints on parameters supressed + + private ArrayList<Object> constraints = null; // user added constraints + private int numberOfAddedConstraints = -1; // number of user added constraints + + private boolean constraintsAdded = false; // = true when user added constraints on parameters entered + + private double[] initialEstimates = null; // initial estimates of parameter values + private double[] initialSteps = null; // initial steps of parameter values + + private double[] bestEstimates = null; // best estimates of parameter values + private double[] standardDeviations = null; // standard deviations of the best estimates + private double[] coefficientsOfVariation = null; // coefficients of variation of the best estimates + private double[][] correlationCoefficients = null; // correlation coefficients of the best estimates + private double[] preMinimumGradients = null; // gradient before the minimum for each parameter + private double[] postMinimumGradients = null; // gradient after the minimum for each parameter + + private int degreesOfFreedom = 0; // degrees of freedom + private double sumOfSquares = 0.0D; // sum of squares at minimum + private double reducedSumOfSquares = 0.0D; // reduced sum of squares at minimum + private double chiSquare = Double.NaN; // chiSquare + private double reducedChiSquare = Double.NaN; // reducedChiSquare + private double[] realZresiduals = null; // Real[Z] residuals + private double[] imagZresiduals = null; // Imag[Z] residuals + + private double[] calculatedRealZ = null; // calculated Real[Z] + private double[] calculatedImagZ = null; // calculated Imag[Z] + private Complex[] calculatedImpedances = null; // calculated model impedances + private double[] calculatedImpedanceMagnitudes = null; // calculated impedance magnitudes + private double[] calculatedImpedancePhasesRad = null; // calculated impedance phases (radians) + private double[] calculatedImpedancePhasesDeg = null; // calculated impedance phases (degrees) + + private double[] calculatedRealV = null; // calculated Real[voltage] + private double[] calculatedImagV = null; // calculated Imag[voltage] + private Complex[] calculatedVoltages = null; // calculated voltages + private double[] calculatedVoltageMagnitudes = null; // calculated voltage magnitudes + private double[] calculatedVoltagePhasesRad = null; // calculated voltage phases (radians) + private double[] calculatedVoltagePhasesDeg = null; // calculated voltage phases (degrees) + + ArrayList<Object> results = null; // ArrayList with elements + // 0: number of frequencies + // 1: number of parameters + // 2: degrees of freedom + // 3: initial estimates + // 4: initial step sizes + // 5: best estimates + // 6: standard deviations + // 7: coefficients of variation + // 8: gradients about the minimum + // 9: reduced sum of squares + // 10: chi square + // 11: reduced chi square + + + private boolean estimatesSet = false; // = true when parameter estimates entered + + private ImpedSpecModel userModel = null; // supplied user model + private boolean userModelSet = false; // = true if user model supplied + private RegressionFunction2 regressionFunction = null; // Regression function + private double tolerance = 1e-9; // tolerance in regression exit test + private int maximumIterations = 10000; // maximum iterations in regression procedure + private int numberOfIterations1 = -1; // number of iterations taken in the first regression + private int numberOfIterations2 = -1; // number of iterations taken in the second regression + private boolean regressionDone = false; // = true when regression completed + + private int numberOfLineFrequencies = 8000; // number of points on calculated line plots + private boolean logOrLinear = true; // = true - log plot + // = false - linear plot + private double[] lineFrequencies = null; // frequencies for clculating theoretical lines + private double[] log10lineFrequencies = null; // log10 of the frequencies for clculating theoretical lines + + + // CONSTRUCTORS + + // Constructor + public ImpedSpecRegression(){ + this.regressionTitle = " "; + } + + // Constructor setting title + public ImpedSpecRegression(String regressionTitle){ + this.regressionTitle = regressionTitle; + } + + // ENTER DATA + + // Enter the applied voltage + public void setAppliedVoltage(double voltage){ + this.appliedVoltage = new Complex(voltage, 0.0D); + this.appliedVoltageError = new Complex(0.0D, 0.0D); + this.appliedVoltageSet = true; + if(this.referenceSet && this.frequenciesSet)this.calculateExperimentalImpedances(); + } + + // Enter the setApplied voltage with error + public void appliedVoltage(double voltage, double voltageError){ + this.appliedVoltage = new Complex(voltage, 0.0D); + this.appliedVoltageSet = true; + this.appliedVoltage = new Complex(voltageError, 0.0D); + this.voltageErrorSet = true; + if(this.referenceSet && this.frequenciesSet)this.calculateExperimentalImpedances(); + } + + // Enter the reference impedance - resistive + public void setReferenceImpedance(double resistance){ + this.referenceImpedance = new Complex(resistance, 0.0D); + this.referenceSet = true; + if(this.appliedVoltageSet && this.frequenciesSet)this.calculateExperimentalImpedances(); + } + + // Enter the reference impedance - reactive + public void setReferenceImpedance(double real, double imag){ + this.referenceImpedance = new Complex(real, imag); + this.referenceSet = true; + if(this.appliedVoltageSet && this.frequenciesSet)this.calculateExperimentalImpedances(); + } + + // Enter the reference impedance - reactive + public void setReferenceImpedance(Complex impedance){ + this.referenceImpedance = impedance; + this.referenceSet = true; + if(this.appliedVoltageSet && this.frequenciesSet)this.calculateExperimentalImpedances(); + } + + // Enter data as frequencies and real and imaginary parts of the test circuit voltages - no weights + public void voltageDataAsComplex(double[] frequencies, double[] real, double[] imag){ + + double[] realWeight = new double[frequencies.length]; + double[] imagWeight = new double[frequencies.length]; + this.weightsSet = false; + this.voltageDataAsComplex(frequencies, real, imag, realWeight, imagWeight); + } + + + // Enter data as frequencies and real and imaginary parts of the test circuit voltages - weights provided + public void voltageDataAsComplex(double[] frequencies, double[] real, double[] imag, double[] realWeight, double[] imagWeight){ + + this.numberOfFrequencies = frequencies.length; + if(this.numberOfFrequencies!=real.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of Real[voltages], " + real.length); + if(this.numberOfFrequencies!=imag.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of Imag[voltages], " + imag.length); + if(this.numberOfFrequencies!=realWeight.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of real weights, " + realWeight.length); + if(this.numberOfFrequencies!=imagWeight.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of imag weights, " + imagWeight.length); + + this.frequencies = (double[])frequencies.clone(); + this.setAllFrequencyArrays(); + this.setCalculatedArrayLengths(); + + this.realV = (double[])real.clone(); + this.imagV = (double[])imag.clone(); + this.realVweights = (double[])realWeight.clone(); + this.imagVweights = (double[])imagWeight.clone(); + this.voltageMagnitudes = new double[this.numberOfFrequencies]; + this.voltagePhasesDeg = new double[this.numberOfFrequencies]; + this.voltagePhasesRad = new double[this.numberOfFrequencies]; + this.voltages = Complex.oneDarray(this.numberOfFrequencies); + for(int i=0; i<this.numberOfFrequencies; i++){ + this.voltages[i] = new Complex(realV[i], imagV[i]); + this.voltageMagnitudes[i] = this.voltages[i].abs(); + this.voltagePhasesRad[i] = this.voltages[i].arg(); + this.voltagePhasesDeg[i] = Math.toDegrees(this.voltagePhasesRad[i]); + } + this.frequenciesSet = true; + + this.setImpedanceArrayLengths(); + this.calculateExperimentalImpedances(); + this.dataEnteredTypePointer = 4; + this.voltageOrImpedance = true; + if(this.estimatesNeeded)this.setInitialEstimates(); + } + + // Enter data as frequencies and Complex test circuit voltages - no weights provided + public void voltageDataAsComplex(double[] frequencies, Complex[] voltages){ + + Complex[] weights = Complex.oneDarray(voltages.length, 0.0D, 0.0D); + this.weightsSet = false; + this.voltageDataAsComplex(frequencies, voltages, weights); + } + + // Enter data as frequencies and Complex voltages - weights provided + // reference - voltage + public void voltageDataAsComplex(double[] frequencies, Complex[] voltages, Complex[] weights){ + + this.numberOfFrequencies = frequencies.length; + if(this.numberOfFrequencies!=voltages.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of voltages, " + voltages.length); + if(this.numberOfFrequencies!=weights.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of weights, " + weights.length); + + this.frequencies = (double[])frequencies.clone(); + this.setAllFrequencyArrays(); + this.setCalculatedArrayLengths(); + + this.voltages = Complex.copy(voltages); + this.voltageWeights = Complex.copy(weights); + this.voltageMagnitudes = new double[this.numberOfFrequencies]; + this.voltagePhasesDeg = new double[this.numberOfFrequencies]; + this.voltagePhasesRad = new double[this.numberOfFrequencies]; + this.realV = new double[this.numberOfFrequencies]; + this.imagV = new double[this.numberOfFrequencies]; + this.realVweights = new double[this.numberOfFrequencies]; + this.imagVweights = new double[this.numberOfFrequencies]; + + for(int i=0; i<this.numberOfFrequencies; i++){ + this.realV[i] = this.voltages[i].getReal(); + this.imagV[i] = this.voltages[i].getImag(); + this.realVweights[i] = weights[i].getReal(); + this.imagVweights[i] = weights[i].getImag(); + this.voltageMagnitudes[i] = this.voltages[i].abs(); + this.voltagePhasesRad[i] = this.voltages[i].arg(); + this.voltagePhasesDeg[i] = Math.toDegrees(this.voltagePhasesRad[i]); + } + this.frequenciesSet = true; + + this.setImpedanceArrayLengths(); + this.calculateExperimentalImpedances(); + this.voltageOrImpedance = true; + this.dataEnteredTypePointer = 1; + if(this.estimatesNeeded)this.setInitialEstimates(); + } + + // Enter data as frequencies and magnitudes and phases (radians) of the test circuit voltages - no weights + public void voltageDataAsPhasorRad(double[] frequencies, double[] voltageMagnitudes, double[] voltagePhasesRad){ + + double[] voltageMagWeights = new double[frequencies.length]; + double[] voltagePhaseWeights = new double[frequencies.length]; + this.weightsSet = false; + this.voltageDataAsPhasorRad(frequencies, voltageMagnitudes, voltagePhasesRad, voltageMagWeights, voltagePhaseWeights); + } + + // Enter data as frequencies and magnitudes and phases (radians) of the voltages - weights provided + public void voltageDataAsPhasorRad(double[] frequencies, double[] voltageMagnitudes, double[] voltagePhasesRad, double[] voltageMagWeights, double[] voltagePhaseWeights){ + + this.numberOfFrequencies = frequencies.length; + if(this.numberOfFrequencies!=voltageMagnitudes.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of magnitudes, " + voltageMagnitudes.length); + if(this.numberOfFrequencies!=voltagePhasesRad.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of phases, " + voltagePhasesRad.length); + if(this.numberOfFrequencies!=voltageMagWeights.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of magnitude weights, " + voltageMagWeights.length); + if(this.numberOfFrequencies!=voltagePhaseWeights.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of phase weights, " + voltagePhaseWeights.length); + + this.frequencies = (double[])frequencies.clone(); + this.setAllFrequencyArrays(); + this.setCalculatedArrayLengths(); + + this.voltageMagnitudes = (double[])voltageMagnitudes.clone(); + this.voltageMagnitudeWeights = (double[])voltageMagWeights.clone(); + this.voltagePhaseWeightsRad = (double[])voltagePhaseWeights.clone(); + this.voltages= Complex.oneDarray(this.numberOfFrequencies); + this.voltagePhasesDeg = new double[this.numberOfFrequencies]; + this.realV = new double[this.numberOfFrequencies]; + this.imagV = new double[this.numberOfFrequencies]; + this.realVweights = new double[this.numberOfFrequencies]; + this.imagVweights = new double[this.numberOfFrequencies]; + + for(int i=0; i<this.numberOfFrequencies; i++){ + this.voltagePhasesDeg[i] = Math.toDegrees(this.voltagePhasesRad[i]); + this.voltages[i].polar(voltageMagnitudes[i], voltagePhasesRad[i]); + this.realV[i] = this.voltages[i].getReal(); + this.imagV[i] = this.voltages[i].getImag(); + ErrorProp mag = new ErrorProp(voltageMagnitudes[i], voltageMagnitudeWeights[i]); + ErrorProp phase = new ErrorProp(voltagePhasesRad[i], voltagePhaseWeights[i]); + ComplexErrorProp volt = new ComplexErrorProp(); + volt.polar(mag, phase); + this.realVweights[i] = volt.getRealError(); + this.imagVweights[i] = volt.getImagError(); + } + this.frequenciesSet = true; + + this.setImpedanceArrayLengths(); + this.calculateExperimentalImpedances(); + this.voltageOrImpedance = true; + this.dataEnteredTypePointer = 2; + if(this.estimatesNeeded)this.setInitialEstimates(); + } + + // Enter data as frequencies and magnitudes and phases (degrees) of the test circuit voltages - no weights + public void voltageDataAsPhasorDeg(double[] frequencies, double[] voltageMagnitudes, double[] voltagePhasesRad){ + + double[] voltageMagWeights = new double[frequencies.length]; + double[] voltagePhaseWeights = new double[frequencies.length]; + this.weightsSet = false; + this.voltageDataAsPhasorDeg(frequencies, voltageMagnitudes, voltagePhasesRad, voltageMagWeights, voltagePhaseWeights); + } + + // Enter data as frequencies and magnitudes and phases of the voltages (degrees) + public void voltageDataAsPhasorDeg(double[] frequencies, double[] voltageMagnitudes, double[] voltagePhasesDeg, double[] voltageMagWeights, double[] voltagePhaseWeights){ + + this.numberOfFrequencies = frequencies.length; + if(this.numberOfFrequencies!=voltageMagnitudes.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of magnitudes, " + voltageMagnitudes.length); + if(this.numberOfFrequencies!=voltagePhasesDeg.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of phases, " + voltagePhasesDeg.length); + if(this.numberOfFrequencies!=voltageMagWeights.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of magnitude weights, " + voltageMagWeights.length); + if(this.numberOfFrequencies!=voltagePhaseWeights.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of phase weights, " + voltagePhaseWeights.length); + + this.frequencies = (double[])frequencies.clone(); + this.setAllFrequencyArrays(); + this.setCalculatedArrayLengths(); + + this.voltageMagnitudes = (double[])voltageMagnitudes.clone(); + this.voltagePhasesDeg = (double[])voltagePhasesDeg.clone(); + this.voltages = Complex.oneDarray(this.numberOfFrequencies); + this.voltagePhasesRad = new double[this.numberOfFrequencies]; + this.voltagePhaseWeightsRad = new double[this.numberOfFrequencies]; + this.voltageMagnitudeWeights = (double[])voltageMagWeights.clone(); + this.voltagePhaseWeightsDeg = (double[])voltagePhaseWeights.clone(); + this.realV = new double[this.numberOfFrequencies]; + this.imagV = new double[this.numberOfFrequencies]; + this.realVweights = new double[this.numberOfFrequencies]; + this.imagVweights = new double[this.numberOfFrequencies]; + for(int i=0; i<this.numberOfFrequencies; i++){ + this.voltagePhasesRad[i] = Math.toRadians(this.voltagePhasesDeg[i]); + this.voltagePhaseWeightsRad[i] = Math.toRadians(voltagePhaseWeights[i]); + this.voltages[i].polar(voltageMagnitudes[i], voltagePhasesRad[i]); + this.realV[i] = this.voltages[i].getReal(); + this.imagV[i] = this.voltages[i].getImag(); + ErrorProp mag = new ErrorProp(voltageMagnitudes[i], voltageMagnitudeWeights[i]); + ErrorProp phase = new ErrorProp(voltagePhasesRad[i], this.voltagePhaseWeightsRad[i]); + ComplexErrorProp volt = new ComplexErrorProp(); + volt.polar(mag, phase); + this.realVweights[i] = volt.getRealError(); + this.imagVweights[i] = volt.getImagError(); + + } + this.frequenciesSet = true; + + this.setImpedanceArrayLengths(); + this.calculateExperimentalImpedances(); + this.voltageOrImpedance = true; + this.dataEnteredTypePointer = 3; + if(this.estimatesNeeded)this.setInitialEstimates(); + } + + // Enter data as frequencies and real and imaginary parts of the impedances - no weights + public void impedanceDataAsComplex(double[] frequencies, double[] real, double[] imag){ + + double[] realWeight = new double[frequencies.length]; + double[] imagWeight = new double[frequencies.length]; + this.weightsSet = false; + this.impedanceDataAsComplex(frequencies, real, imag, realWeight, imagWeight); + } + + + // Enter data as frequencies and real and imaginary parts of the impedances - weights provided + public void impedanceDataAsComplex(double[] frequencies, double[] real, double[] imag, double[] realWeight, double[] imagWeight){ + + this.numberOfFrequencies = frequencies.length; + if(this.numberOfFrequencies!=real.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of Real[impedances], " + real.length); + if(this.numberOfFrequencies!=imag.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of Imag[impedances], " + imag.length); + if(this.numberOfFrequencies!=realWeight.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of real weights, " + realWeight.length); + if(this.numberOfFrequencies!=imagWeight.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of imag weights, " + imagWeight.length); + + this.frequencies = (double[])frequencies.clone(); + this.setAllFrequencyArrays(); + this.setCalculatedArrayLengths(); + + this.realZ = (double[])real.clone(); + this.imagZ = (double[])imag.clone(); + this.realZweights = (double[])realWeight.clone(); + this.imagZweights = (double[])imagWeight.clone(); + this.impedanceMagnitudes = new double[this.numberOfFrequencies]; + this.impedancePhasesDeg = new double[this.numberOfFrequencies]; + this.impedancePhasesRad = new double[this.numberOfFrequencies]; + this.impedances = Complex.oneDarray(this.numberOfFrequencies); + for(int i=0; i<this.numberOfFrequencies; i++){ + this.impedances[i] = new Complex(realZ[i], imagZ[i]); + this.impedanceMagnitudes[i] = this.impedances[i].abs(); + this.impedancePhasesRad[i] = this.impedances[i].arg(); + this.impedancePhasesDeg[i] = Math.toDegrees(this.impedancePhasesRad[i]); + } + this.frequenciesSet = true; + this.impedancesSet = true; + + this.dataEnteredTypePointer = 4; + this.voltageOrImpedance = false; + if(this.estimatesNeeded)this.setInitialEstimates(); + } + + // Enter data as frequencies and Complex impedances - no weights provided + public void impedanceDataAsComplex(double[] frequencies, Complex[] impedances){ + + Complex[] weights = Complex.oneDarray(impedances.length, 0.0D, 0.0D); + this.weightsSet = false; + this.impedanceDataAsComplex(frequencies, impedances, weights); + } + + // Enter data as frequencies and Complex impedances - weights provided + public void impedanceDataAsComplex(double[] frequencies, Complex[] impedances, Complex[] weights){ + + this.numberOfFrequencies = frequencies.length; + if(this.numberOfFrequencies!=impedances.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of impedances, " + impedances.length); + if(this.numberOfFrequencies!=weights.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of weights, " + weights.length); + + this.frequencies = (double[])frequencies.clone(); + this.setAllFrequencyArrays(); + this.setCalculatedArrayLengths(); + + this.impedances = Complex.copy(impedances); + this.impedanceWeights = Complex.copy(weights); + this.impedanceMagnitudes = new double[this.numberOfFrequencies]; + this.impedancePhasesDeg = new double[this.numberOfFrequencies]; + this.impedancePhasesRad = new double[this.numberOfFrequencies]; + this.realZ = new double[this.numberOfFrequencies]; + this.imagZ = new double[this.numberOfFrequencies]; + this.realZweights = new double[this.numberOfFrequencies]; + this.imagZweights = new double[this.numberOfFrequencies]; + + for(int i=0; i<this.numberOfFrequencies; i++){ + this.realZ[i] = this.impedances[i].getReal(); + this.imagZ[i] = this.impedances[i].getImag(); + this.realZweights[i] = weights[i].getReal(); + this.imagZweights[i] = weights[i].getImag(); + this.impedanceMagnitudes[i] = this.impedances[i].abs(); + this.impedancePhasesRad[i] = this.impedances[i].arg(); + this.impedancePhasesDeg[i] = Math.toDegrees(this.impedancePhasesRad[i]); + } + this.frequenciesSet = true; + this.impedancesSet = true; + + this.voltageOrImpedance = false; + this.dataEnteredTypePointer = 5; + if(this.estimatesNeeded)this.setInitialEstimates(); + } + + // Enter data as frequencies and magnitudes and phases (radians) of the impedances - no weights + public void impedanceDataAsPhasorRad(double[] frequencies, double[] impedanceMagnitudes, double[] impedancePhasesRad){ + + double[] impedanceMagWeights = new double[frequencies.length]; + double[] impedancePhaseWeights = new double[frequencies.length]; + this.weightsSet = false; + this.impedanceDataAsPhasorRad(frequencies, impedanceMagnitudes, impedancePhasesRad, impedanceMagWeights, impedancePhaseWeights); + } + + // Enter data as frequencies and magnitudes and phases (radians) of the impedances - weights provided + public void impedanceDataAsPhasorRad(double[] frequencies, double[] impedanceMagnitudes, double[] impedancePhasesRad, double[] impedanceMagWeights, double[] impedancePhaseWeights){ + + this.numberOfFrequencies = frequencies.length; + if(this.numberOfFrequencies!=impedanceMagnitudes.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of magnitudes, " + impedanceMagnitudes.length); + if(this.numberOfFrequencies!=impedancePhasesRad.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of phases, " + impedancePhasesRad.length); + if(this.numberOfFrequencies!=impedanceMagWeights.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of magnitude weights, " + impedanceMagWeights.length); + if(this.numberOfFrequencies!=impedancePhaseWeights.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of phase weights, " + impedancePhaseWeights.length); + + this.frequencies = (double[])frequencies.clone(); + this.setAllFrequencyArrays(); + this.setCalculatedArrayLengths(); + + this.impedanceMagnitudes = (double[])impedanceMagnitudes.clone(); + this.impedanceMagnitudeWeights = (double[])impedanceMagWeights.clone(); + this.impedancePhaseWeightsRad = (double[])impedancePhaseWeights.clone(); + this.impedances= Complex.oneDarray(this.numberOfFrequencies); + this.impedancePhasesDeg = new double[this.numberOfFrequencies]; + this.realZ = new double[this.numberOfFrequencies]; + this.imagZ = new double[this.numberOfFrequencies]; + this.realZweights = new double[this.numberOfFrequencies]; + this.imagZweights = new double[this.numberOfFrequencies]; + + for(int i=0; i<this.numberOfFrequencies; i++){ + this.impedancePhasesDeg[i] = Math.toDegrees(this.impedancePhasesRad[i]); + this.impedances[i].polar(impedanceMagnitudes[i], impedancePhasesRad[i]); + this.realZ[i] = this.impedances[i].getReal(); + this.imagZ[i] = this.impedances[i].getImag(); + ErrorProp mag = new ErrorProp(impedanceMagnitudes[i], impedanceMagnitudeWeights[i]); + ErrorProp phase = new ErrorProp(impedancePhasesRad[i], impedancePhaseWeights[i]); + ComplexErrorProp volt = new ComplexErrorProp(); + volt.polar(mag, phase); + this.realZweights[i] = volt.getRealError(); + this.imagZweights[i] = volt.getImagError(); + } + this.frequenciesSet = true; + this.impedancesSet = true; + + this.voltageOrImpedance = false; + this.dataEnteredTypePointer = 6; + if(this.estimatesNeeded)this.setInitialEstimates(); + } + + // Enter data as frequencies and magnitudes and phases (degrees) of the impedances - no weights + public void impedanceDataAsPhasorDeg(double[] frequencies, double[] impedanceMagnitudes, double[] impedancePhasesRad){ + + double[] impedanceMagWeights = new double[frequencies.length]; + double[] impedancePhaseWeights = new double[frequencies.length]; + this.weightsSet = false; + this.impedanceDataAsPhasorDeg(frequencies, impedanceMagnitudes, impedancePhasesRad, impedanceMagWeights, impedancePhaseWeights); + } + + // Enter data as frequencies and magnitudes and phases of the impedances (degrees) + public void impedanceDataAsPhasorDeg(double[] frequencies, double[] impedanceMagnitudes, double[] impedancePhasesDeg, double[] impedanceMagWeights, double[] impedancePhaseWeights){ + + this.numberOfFrequencies = frequencies.length; + if(this.numberOfFrequencies!=impedanceMagnitudes.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of magnitudes, " + impedanceMagnitudes.length); + if(this.numberOfFrequencies!=impedancePhasesDeg.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of phases, " + impedancePhasesDeg.length); + if(this.numberOfFrequencies!=impedanceMagWeights.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of magnitude weights, " + impedanceMagWeights.length); + if(this.numberOfFrequencies!=impedancePhaseWeights.length)throw new IllegalArgumentException("The number of frequencies, " + this.numberOfFrequencies + ", does not equal the number of phase weights, " + impedancePhaseWeights.length); + + this.frequencies = (double[])frequencies.clone(); + this.setAllFrequencyArrays(); + this.setCalculatedArrayLengths(); + + this.impedanceMagnitudes = (double[])impedanceMagnitudes.clone(); + this.impedancePhasesDeg = (double[])impedancePhasesDeg.clone(); + this.impedances = Complex.oneDarray(this.numberOfFrequencies); + this.impedancePhasesRad = new double[this.numberOfFrequencies]; + this.impedancePhaseWeightsRad = new double[this.numberOfFrequencies]; + this.impedanceMagnitudeWeights = (double[])impedanceMagWeights.clone(); + this.impedancePhaseWeightsDeg = (double[])impedancePhaseWeights.clone(); + this.realZ = new double[this.numberOfFrequencies]; + this.imagZ = new double[this.numberOfFrequencies]; + this.realZweights = new double[this.numberOfFrequencies]; + this.imagZweights = new double[this.numberOfFrequencies]; + + for(int i=0; i<this.numberOfFrequencies; i++){ + this.impedancePhasesRad[i] = Math.toRadians(this.impedancePhasesDeg[i]); + this.impedancePhaseWeightsRad[i] = Math.toRadians(impedancePhaseWeights[i]); + this.impedances[i].polar(impedanceMagnitudes[i], impedancePhasesRad[i]); + this.realZ[i] = this.impedances[i].getReal(); + this.imagZ[i] = this.impedances[i].getImag(); + ErrorProp mag = new ErrorProp(impedanceMagnitudes[i], impedanceMagnitudeWeights[i]); + ErrorProp phase = new ErrorProp(impedancePhasesRad[i], this.impedancePhaseWeightsRad[i]); + ComplexErrorProp volt = new ComplexErrorProp(); + volt.polar(mag, phase); + this.realZweights[i] = volt.getRealError(); + this.imagZweights[i] = volt.getImagError(); + + } + this.frequenciesSet = true; + this.impedancesSet = true; + + this.voltageOrImpedance = false; + this.dataEnteredTypePointer = 7; + if(this.estimatesNeeded)this.setInitialEstimates(); + } + + // Set all frequency + private void setAllFrequencyArrays(){ + + this.log10frequencies = new double[this.numberOfFrequencies]; + this.omegas = new double[this.numberOfFrequencies]; + this.log10omegas = new double[this.numberOfFrequencies]; + for(int i=0; i<this.numberOfFrequencies; i++){ + this.log10frequencies[i] = Math.log10(frequencies[i]); + this.omegas[i] = 2.0D*Math.PI*frequencies[i]; + this.log10omegas[i] = Math.log10(omegas[i]); + } + this.frequenciesSet = true; + } + + // Set all calculted array lengths + private void setCalculatedArrayLengths(){ + + this.realZresiduals = new double[this.numberOfFrequencies]; + this.imagZresiduals = new double[this.numberOfFrequencies]; + this.calculatedRealZ = new double[this.numberOfFrequencies]; + this.calculatedImagZ = new double[this.numberOfFrequencies]; + this.calculatedImpedances = Complex.oneDarray(this.numberOfFrequencies); + this.calculatedImpedanceMagnitudes = new double[this.numberOfFrequencies]; + this.calculatedImpedancePhasesRad = new double[this.numberOfFrequencies]; + this.calculatedImpedancePhasesDeg = new double[this.numberOfFrequencies]; + + if(this.appliedVoltageSet && this.referenceSet){ + this.calculatedRealV = new double[this.numberOfFrequencies]; + this.calculatedImagV = new double[this.numberOfFrequencies]; + this.calculatedVoltages = Complex.oneDarray(this.numberOfFrequencies); + this.calculatedVoltageMagnitudes = new double[this.numberOfFrequencies]; + this.calculatedVoltagePhasesRad = new double[this.numberOfFrequencies]; + this.calculatedVoltagePhasesDeg = new double[this.numberOfFrequencies]; + } + } + + // Set the impedance array lengths + private void setImpedanceArrayLengths(){ + + this.realZ = new double[this.numberOfFrequencies]; + this.imagZ = new double[this.numberOfFrequencies]; + this.realZweights = new double[this.numberOfFrequencies]; + this.imagZweights = new double[this.numberOfFrequencies]; + this.impedances = Complex.oneDarray(this.numberOfFrequencies); + this.impedanceMagnitudes = new double[this.numberOfFrequencies]; + this.impedancePhasesRad = new double[this.numberOfFrequencies]; + this.impedancePhasesDeg = new double[this.numberOfFrequencies]; + } + + // Calculate the experimental impedances if voltages have been entered + private void calculateExperimentalImpedances(){ + if(this.referenceSet && this.appliedVoltageSet){ + for(int i=0; i<this.numberOfFrequencies; i++){ + // voltage divider calculation + + this.impedances[i] = (this.referenceImpedance.times(this.voltages[i])).over(this.appliedVoltage.minus(this.voltages[i])); + + this.realZ[i] = this.impedances[i].getReal(); + this.imagZ[i] = this.impedances[i].getImag(); + + this.impedanceMagnitudes[i] = this.impedances[i].abs(); + this.impedancePhasesRad[i] = this.impedances[i].arg(); + this.impedancePhasesDeg[i] = Math.toDegrees(this.impedancePhasesRad[i]); + + if(this.weightsSet && this.voltageErrorSet){ + ComplexErrorProp appliedV = new ComplexErrorProp(this.appliedVoltage.getReal(), this.appliedVoltageError.getReal(), this.appliedVoltage.getImag(), this.appliedVoltageError.getImag()); + ComplexErrorProp expertlV = new ComplexErrorProp(this.realV[i], this.realVweights[i], this.imagV[i], this.imagVweights[i]); + ComplexErrorProp refImped = new ComplexErrorProp(this.referenceImpedance.getReal(), 0.0D, this.referenceImpedance.getImag(), 0.0D); + ComplexErrorProp eVoverAv = (expertlV.over(appliedV)).times(refImped); + this.realZweights[i] = eVoverAv.getRealError(); + this.imagZweights[i] = eVoverAv.getImagError(); + } + this.impedancesSet = true; + } + } + } + + + // ENTER THE MODEL + + // Enter user supplied model, parameter symbols, initial estimates and initial steps + public void setModel(ImpedSpecModel userModel, String[] symbols, double[] initialEstimates, double[] initialSteps){ + + this.userModel = userModel; + this.parameterSymbols = symbols; + this.numberOfParameters = symbols.length; + if(this.numberOfParameters!=initialEstimates.length)throw new IllegalArgumentException("The number of parameter symbols, " + this.numberOfParameters + ", does not equal the number of initial estimates, " + initialEstimates.length); + if(this.numberOfParameters!=initialSteps.length)throw new IllegalArgumentException("The number of parameter symbols, " + this.numberOfParameters + ", does not equal the number of initial steps, " + initialSteps.length); + this.initialEstimates = initialEstimates; + this.initialSteps = initialSteps; + this.setEstimateArrayDimensions(); + this.estimatesSet = true; + this.userModelSet = true; + } + + // Enter user supplied model, parameter symbols, initial estimates and initial steps calculated as 10% of initial estimates + public void setModel(ImpedSpecModel userModel, String[] symbols, double[] initialEstimates){ + + this.userModel = userModel; + this.parameterSymbols = symbols; + this.numberOfParameters = symbols.length; + if(this.numberOfParameters!=initialEstimates.length)throw new IllegalArgumentException("The number of parameter symbols, " + this.numberOfParameters + ", does not equal the number of initial estimates, " + initialEstimates.length); + this.initialEstimates = initialEstimates; + this.initialSteps = new double[this.numberOfParameters]; + for(int i=0; i<this.numberOfParameters; i++)this.initialSteps[i] = Math.abs(this.initialEstimates[i])*0.1D; + this.setEstimateArrayDimensions(); + this.estimatesSet = true; + this.userModelSet = true; + } + + // Enter the model number, initial estimates and initial steps + public void setModel(int modelNumber, double[] initialEstimates, double[] initialSteps){ + + this.numberOfParameters = initialEstimates.length; + if(this.numberOfParameters!=Impedance.modelComponents(modelNumber).length)throw new IllegalArgumentException("The number of parameter estimates, " + this.numberOfParameters + ", does not equal the number of parameters, " + Impedance.modelComponents(modelNumber).length + ", in model number " + modelNumber); + if(this.numberOfParameters!=initialSteps.length)throw new IllegalArgumentException("The number of parameter estimates, " + this.numberOfParameters + ", does not equal the number of parameter steps, " + initialSteps.length); + + this.modelNumber = modelNumber; + this.initialEstimates = initialEstimates; + this.initialSteps = initialSteps; + this.parameterSymbols = Impedance.modelComponents(modelNumber); + this.setEstimateArrayDimensions(); + this.estimatesSet = true; + this.modelSet = true; + } + + // Enter the model number and initial estimates - parameter steps calculated as 10% of initial estimated + public void setModel(int modelNumber, double[] initialEstimates){ + + this.numberOfParameters = initialEstimates.length; + if(this.numberOfParameters!=Impedance.modelComponents(modelNumber).length)throw new IllegalArgumentException("The number of parameter estimates, " + this.numberOfParameters + ", does not equal the number of parameters, " + Impedance.modelComponents(modelNumber).length + ", in model number " + modelNumber); + + this.modelNumber = modelNumber; + this.initialEstimates = initialEstimates; + this.parameterSymbols = Impedance.modelComponents(modelNumber); + this.initialSteps = new double[this.numberOfParameters]; + for(int i=0; i<this.numberOfParameters; i++)this.initialSteps[i] = Math.abs(this.initialEstimates[i])*0.1D; + this.setEstimateArrayDimensions(); + this.estimatesSet = true; + this.modelSet = true; + } + + // Enter the model number - parameters estimated by the method + public void setModel(int modelNumber){ + + this.modelNumber = modelNumber; + this.parameterSymbols = Impedance.modelComponents(modelNumber); + this.numberOfParameters = this.parameterSymbols.length; + + this.setEstimateArrayDimensions(); + + // initial estimates + this.setInitialEstimates(); + this.estimatesSet = true; + + this.modelSet = true; + } + + // Set dimensions of best estimates and associated arrays + private void setEstimateArrayDimensions(){ + + this.bestEstimates = new double[this.numberOfParameters]; + this.standardDeviations = new double[this.numberOfParameters]; + this.coefficientsOfVariation = new double[this.numberOfParameters]; + this.preMinimumGradients = new double[this.numberOfParameters]; + this.postMinimumGradients = new double[this.numberOfParameters]; + + this.correlationCoefficients = new double[this.numberOfParameters][this.numberOfParameters]; + } + + // Provide initial estimates for a given model number + private void setInitialEstimates(){ + if(this.impedancesSet && this.frequenciesSet){ + + this.degreesOfFreedom = this.numberOfFrequencies - this.numberOfParameters; + if(this.degreesOfFreedom<=0)throw new IllegalArgumentException("Degrees of freedom, " + this.degreesOfFreedom + ", are less than 1"); + + double meanRealZ = Stat.mean(this.realZ); + double minRealZ = Fmath.minimum(this.realZ); + int indexMinRealZ = Fmath.indexOf(this.realZ, minRealZ); + double maxRealZ = Fmath.maximum(this.realZ); + int indexMaxRealZ = Fmath.indexOf(this.realZ, maxRealZ); + + double meanImagZ = Stat.mean(this.imagZ); + double minImagZ = Fmath.minimum(this.imagZ); + int indexMinImagZ = Fmath.indexOf(this.imagZ, minImagZ); + double maxImagZ = Fmath.maximum(this.imagZ); + int indexMaxImagZ = Fmath.indexOf(this.imagZ, maxImagZ); + + double imagBig = Math.max(Math.abs(minImagZ),Math.abs(maxImagZ)); + int bigIndex = Fmath.indexOf(this.imagZ, imagBig); + if(bigIndex==-1)bigIndex = Fmath.indexOf(this.imagZ, -imagBig); + if(bigIndex==-1)bigIndex = this.numberOfFrequencies/2; + + double geometricFreqMean = Stat.geometricMean(this.log10frequencies); + + switch(this.modelNumber){ + case 1: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[0] = meanRealZ; + break; + case 2: this.initialEstimates = new double[this.numberOfParameters]; + double sumC = 0.0; + for(int i=0; i<this.numberOfFrequencies; i++)sumC += 1.0D/Math.abs(this.imagZ[i]*this.omegas[i]); + this.initialEstimates[0] = sumC/this.numberOfFrequencies; + break; + case 3: this.initialEstimates = new double[this.numberOfParameters]; + double sumL = 0.0; + for(int i=0; i<this.numberOfFrequencies; i++)sumL += Math.abs(this.imagZ[i]/this.omegas[i]); + this.initialEstimates[0] = sumL/this.numberOfFrequencies; + break; + case 4: this.initialEstimates = new double[this.numberOfParameters]; + double sumW = 0.0; + for(int i=0; i<this.numberOfFrequencies; i++){ + sumW += Math.abs(this.realZ[i]*Math.sqrt(this.omegas[i])); + sumW += Math.abs(this.imagZ[i]*Math.sqrt(this.omegas[i])); + } + this.initialEstimates[0] = sumW/(2.0D*this.numberOfFrequencies); + break; + case 5: this.initialEstimates = new double[this.numberOfParameters]; + double sumF = 0.0; + for(int i=0; i<this.numberOfFrequencies; i++){ + sumF += Math.abs(this.realZ[i]*Math.sqrt(this.omegas[i])); + sumF += Math.abs(this.imagZ[i]*Math.sqrt(this.omegas[i])); + } + this.initialEstimates[0] = sumF/(2.0D*this.numberOfFrequencies); + this.initialEstimates[1] = Math.abs(meanRealZ/this.initialEstimates[0]); + break; + case 6: this.initialEstimates = new double[this.numberOfParameters]; + double sumQ = 0.0; + for(int i=0; i<this.numberOfFrequencies; i++)sumQ += this.imagZ[i]/this.realZ[i]; + sumQ /= this.numberOfFrequencies; + double theta = Math.abs(Math.atan(sumQ)); + double cosTheta = Math.cos(theta); + double sinTheta = Math.sin(theta); + this.initialEstimates[1] = theta/(Math.PI/2.0); + double sigmaQ = 0.0; + for(int i=0; i<this.numberOfFrequencies; i++){ + sigmaQ += Math.abs(realZ[i]/(cosTheta*Math.pow(this.omegas[i], this.initialEstimates[1]))); + sigmaQ += Math.abs(imagZ[i]/(sinTheta*Math.pow(this.omegas[i], this.initialEstimates[1]))); + } + this.initialEstimates[0] = sigmaQ/(2.0D*this.numberOfFrequencies); + break; + case 7: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[0] = meanRealZ; + double sumC7 = 0.0; + for(int i=0; i<this.numberOfFrequencies; i++)sumC7 += 1.0D/Math.abs(this.imagZ[i]*this.omegas[i]); + this.initialEstimates[1] = sumC7/this.numberOfFrequencies; + break; + case 8: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[0] = meanRealZ; + double sumL8 = 0.0; + for(int i=0; i<this.numberOfFrequencies; i++)sumL8 += Math.abs(this.imagZ[i]/this.omegas[i]); + this.initialEstimates[1] = sumL8/this.numberOfFrequencies; + break; + case 9: this.initialEstimates = new double[this.numberOfParameters]; + double sumL9 = 0.0; + double sumC9 = 0.0; + for(int i=1; i<this.numberOfFrequencies; i++){ + double cC9 = ((this.frequencies[i] - this.frequencies[i-1])/this.frequencies[i])/(this.imagZ[i]*this.frequencies[i-1] - this.imagZ[i-1]*this.frequencies[i]); + double lL9 = (this.imagZ[i] + 1.0D/(cC9*this.frequencies[i]))/this.frequencies[i]; + sumL9 += lL9; + sumC9 += cC9; + } + this.initialEstimates[0] = sumL9/(this.numberOfFrequencies - 1); + this.initialEstimates[1] = sumC9/(this.numberOfFrequencies - 1); + break; + case 10: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[0] = maxRealZ; + this.initialEstimates[1] = 1.0D/(maxRealZ*this.frequencies[indexMinImagZ]); + break; + case 11: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[0] = maxRealZ; + this.initialEstimates[1] = maxRealZ/this.frequencies[indexMaxImagZ]; + break; + case 12: this.initialEstimates = new double[this.numberOfParameters]; + double cL12 = 1/this.frequencies[indexMinImagZ]; + double sumL12 = 0.0; + double sumC12 = 0.0; + for(int i=1; i<this.numberOfFrequencies; i++){ + double c12 = this.imagZ[i]*(this.frequencies[i]*cL12 - 1.0/this.frequencies[i]); + sumL12 += c12; + sumC12 += cL12/c12; + } + this.initialEstimates[0] = sumL12/this.numberOfFrequencies; + this.initialEstimates[1] = sumC12/this.numberOfFrequencies; + break; + case 13: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[2] = minRealZ; + this.initialEstimates[0] = maxRealZ - minRealZ; + this.initialEstimates[1] = 1.0D/(this.initialEstimates[0]*this.frequencies[indexMinImagZ]); + break; + case 14: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[2] = minRealZ; + this.initialEstimates[0] = maxRealZ - minRealZ; + double sumL14 = 0.0; + double sumC14 = 0.0; + for(int i=1; i<this.numberOfFrequencies; i++){ + double cC14 = ((this.frequencies[i] - this.frequencies[i-1])/this.frequencies[i])/(this.imagZ[i]*this.frequencies[i-1] - this.imagZ[i-1]*this.frequencies[i]); + double lL14 = (this.imagZ[i] + 1.0D/(cC14*this.frequencies[i]))/this.frequencies[i]; + sumL14 += lL14; + sumC14 += cC14; + } + this.initialEstimates[3] = sumL14/(this.numberOfFrequencies - 1); + this.initialEstimates[1] = sumC14/(this.numberOfFrequencies - 1); + break; + case 15: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[2] = minRealZ; + this.initialEstimates[0] = maxRealZ - minRealZ; + double cL15 = 1/this.frequencies[indexMinImagZ]; + double sumL15 = 0.0; + double sumC15 = 0.0; + for(int i=1; i<this.numberOfFrequencies; i++){ + double c15 = this.imagZ[i]*(this.frequencies[i]*cL15 - 1.0/this.frequencies[i]); + sumL15 += c15; + sumC15 += cL15/c15; + } + this.initialEstimates[3] = sumL15/this.numberOfFrequencies; + this.initialEstimates[1] = sumC15/this.numberOfFrequencies; + break; + case 16: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[0] = maxRealZ; + double sumC16 = 0.0; + for(int i=0; i<this.numberOfFrequencies; i++)sumC16 += 1.0D/Math.abs(this.imagZ[i]*this.omegas[i]); + this.initialEstimates[1] = 2.0D*sumC16/this.numberOfFrequencies; + this.initialEstimates[2] = this.initialEstimates[1]; + break; + case 17: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[0] = maxRealZ; + double sumC17 = 0.0; + for(int i=0; i<this.numberOfFrequencies; i++)sumC17 += 1.0D/Math.abs(this.imagZ[i]*this.omegas[i]); + this.initialEstimates[1] = sumC17/(2.0D*this.numberOfFrequencies); + this.initialEstimates[2] = this.initialEstimates[1]; + case 18: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[0] = minRealZ; + this.initialEstimates[2] = maxRealZ - minRealZ; + double sumC18 = 0.0; + for(int i=0; i<this.numberOfFrequencies; i++)sumC18 += 1.0D/Math.abs(this.imagZ[i]*this.omegas[i]); + this.initialEstimates[1] = 2.0D*sumC18/this.numberOfFrequencies; + this.initialEstimates[3] = this.initialEstimates[1]; + break; + case 19: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[0] = maxRealZ/2.0D; + this.initialEstimates[2] = this.initialEstimates[0]; + this.initialEstimates[1] = 2.0D/(this.initialEstimates[0]*this.frequencies[indexMinImagZ]); + this.initialEstimates[3] = this.initialEstimates[1]; + break; + case 20: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[4] = minRealZ; + this.initialEstimates[0] = (maxRealZ - minRealZ)/2.0D; + this.initialEstimates[2] = this.initialEstimates[0]; + this.initialEstimates[1] = 2.0D/(this.initialEstimates[0]*this.frequencies[indexMinImagZ]); + this.initialEstimates[3] = this.initialEstimates[1]; + break; + case 21: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[4] = minRealZ; + this.initialEstimates[0] = (maxRealZ - minRealZ)/2.0D; + this.initialEstimates[2] = this.initialEstimates[0]; + double sumC21 = 0.0; + for(int i=0; i<this.numberOfFrequencies; i++)sumC21 += 1.0D/Math.abs(this.imagZ[i]*this.omegas[i]); + this.initialEstimates[1] = sumC21/(2.0D*this.numberOfFrequencies); + this.initialEstimates[3] = this.initialEstimates[1]; + break; + case 22: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[0] = maxRealZ/3.0D; + this.initialEstimates[2] = this.initialEstimates[0]; + this.initialEstimates[4] = this.initialEstimates[0]; + this.initialEstimates[1] = 3.0D/(this.initialEstimates[0]*this.frequencies[indexMinImagZ]); + this.initialEstimates[3] = this.initialEstimates[1]; + this.initialEstimates[5] = this.initialEstimates[1]; + break; + case 23: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[6] = minRealZ; + this.initialEstimates[0] = (maxRealZ - minRealZ)/3.0D; + this.initialEstimates[2] = this.initialEstimates[0]; + this.initialEstimates[4] = this.initialEstimates[0]; + this.initialEstimates[1] = 3.0D/(this.initialEstimates[0]*this.frequencies[indexMinImagZ]); + this.initialEstimates[3] = this.initialEstimates[1]; + this.initialEstimates[5] = this.initialEstimates[1]; + break; + case 24: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[3] = minRealZ; + this.initialEstimates[0] = maxRealZ - minRealZ; + double sumW24 = 0.0; + if(indexMinImagZ<this.numberOfFrequencies-3){ + this.initialEstimates[1] = 1.0D/(this.initialEstimates[0]*this.frequencies[indexMinImagZ]); + for(int i=indexMinImagZ; i<this.numberOfFrequencies; i++){ + sumW24 += Math.abs(this.realZ[i]*Math.sqrt(this.omegas[i])); + sumW24 += Math.abs(this.imagZ[i]*Math.sqrt(this.omegas[i])); + } + this.initialEstimates[2] = sumW24/(2.0D*(this.numberOfFrequencies - indexMinImagZ)); + } + else{ + this.initialEstimates[1] = 1.0D/(this.initialEstimates[0]*geometricFreqMean); + for(int i=0; i<this.numberOfFrequencies; i++){ + sumW24 += Math.abs(this.realZ[i]*Math.sqrt(this.omegas[i])); + sumW24 += Math.abs(this.imagZ[i]*Math.sqrt(this.omegas[i])); + } + this.initialEstimates[2] = sumW24/(2.0D*this.numberOfFrequencies); + } + break; + case 25: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[4] = minRealZ; + this.initialEstimates[0] = maxRealZ - minRealZ; + double sumF25 = 0.0; + if(indexMinImagZ<this.numberOfFrequencies-3){ + this.initialEstimates[1] = 1.0D/(this.initialEstimates[0]*this.frequencies[indexMinImagZ]); + for(int i=indexMinImagZ; i<this.numberOfFrequencies; i++){ + sumF25 += Math.abs(this.realZ[i]*Math.sqrt(this.omegas[i])); + sumF25 += Math.abs(this.imagZ[i]*Math.sqrt(this.omegas[i])); + } + this.initialEstimates[2] = sumF25/(2.0D*(this.numberOfFrequencies - indexMinImagZ)); + this.initialEstimates[3] = Math.abs(meanRealZ/this.initialEstimates[2]); + } + else{ + this.initialEstimates[1] = 1.0D/(this.initialEstimates[0]*geometricFreqMean); + for(int i=0; i<this.numberOfFrequencies; i++){ + sumF25 += Math.abs(this.realZ[i]*Math.sqrt(this.omegas[i])); + sumF25 += Math.abs(this.imagZ[i]*Math.sqrt(this.omegas[i])); + } + this.initialEstimates[2] = sumF25/(2.0D*this.numberOfFrequencies); + this.initialEstimates[3] = Math.abs(meanRealZ/this.initialEstimates[2]); + } + break; + case 26: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[4] = minRealZ; + this.initialEstimates[0] = maxRealZ - minRealZ; + double sumQ26 = 0.0; + if(indexMinImagZ<this.numberOfFrequencies-3){ + this.initialEstimates[1] = 1.0D/(this.initialEstimates[0]*this.frequencies[indexMinImagZ]); + for(int i=indexMinImagZ; i<this.numberOfFrequencies; i++)sumQ26 += this.imagZ[i]/this.realZ[i]; + sumQ26 /= (this.numberOfFrequencies - indexMinImagZ); + double theta26 = Math.abs(Math.atan(sumQ26)); + double cosTheta26 = Math.cos(theta26); + double sinTheta26 = Math.sin(theta26); + this.initialEstimates[3] = theta26/(Math.PI/2.0); + double sigmaQ26 = 0.0; + for(int i=indexMinImagZ; i<this.numberOfFrequencies; i++){ + sigmaQ26 += Math.abs(realZ[i]/(cosTheta26*Math.pow(this.omegas[i], this.initialEstimates[1]))); + sigmaQ26 += Math.abs(imagZ[i]/(sinTheta26*Math.pow(this.omegas[i], this.initialEstimates[1]))); + } + this.initialEstimates[2] = sigmaQ26/(2.0D*(this.numberOfFrequencies - indexMinImagZ)); + } + else{ + this.initialEstimates[1] = 1.0D/(this.initialEstimates[0]*geometricFreqMean); + for(int i=0; i<this.numberOfFrequencies; i++)sumQ26 += this.imagZ[i]/this.realZ[i]; + sumQ26 /= this.numberOfFrequencies; + double theta26 = Math.abs(Math.atan(sumQ26)); + double cosTheta26 = Math.cos(theta26); + double sinTheta26 = Math.sin(theta26); + this.initialEstimates[3] = theta26/(Math.PI/2.0); + double sigmaQ26 = 0.0; + for(int i=0; i<this.numberOfFrequencies; i++){ + sigmaQ26 += Math.abs(realZ[i]/(cosTheta26*Math.pow(this.omegas[i], this.initialEstimates[1]))); + sigmaQ26 += Math.abs(imagZ[i]/(sinTheta26*Math.pow(this.omegas[i], this.initialEstimates[1]))); + } + this.initialEstimates[2] = sigmaQ26/(2.0D*this.numberOfFrequencies); + } + break; + case 27: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[0] = maxRealZ/2.0D; + this.initialEstimates[2] = this.initialEstimates[0]; + double sumW27 = 0.0; + if(indexMinImagZ<this.numberOfFrequencies-3){ + this.initialEstimates[1] = 2.0D/(this.initialEstimates[0]*this.frequencies[indexMinImagZ]); + this.initialEstimates[3] = this.initialEstimates[1]; + for(int i=indexMinImagZ; i<this.numberOfFrequencies; i++){ + sumW27 += Math.abs(this.realZ[i]*Math.sqrt(this.omegas[i])); + sumW27 += Math.abs(this.imagZ[i]*Math.sqrt(this.omegas[i])); + } + this.initialEstimates[4] = sumW27/(2.0D*(this.numberOfFrequencies - indexMinImagZ)); + } + else{ + this.initialEstimates[1] = 2.0D/(this.initialEstimates[0]*geometricFreqMean); + this.initialEstimates[3] = this.initialEstimates[1]; + for(int i=indexMinImagZ; i<this.numberOfFrequencies; i++){ + sumW27 += Math.abs(this.realZ[i]*Math.sqrt(this.omegas[i])); + sumW27 += Math.abs(this.imagZ[i]*Math.sqrt(this.omegas[i])); + } + this.initialEstimates[4] = sumW27/(2.0D*this.numberOfFrequencies); + } + break; + case 28: this.initialEstimates = new double[this.numberOfParameters]; + this.initialEstimates[6] = minRealZ; + this.initialEstimates[0] = (maxRealZ - minRealZ)/2.0D; + this.initialEstimates[2] = this.initialEstimates[0]; + double sumW28 = 0.0; + if(indexMinImagZ<this.numberOfFrequencies-3){ + this.initialEstimates[1] = 3.0D/(this.initialEstimates[0]*this.frequencies[indexMinImagZ]); + this.initialEstimates[3] = this.initialEstimates[1]; + this.initialEstimates[5] = this.initialEstimates[1]; + for(int i=indexMinImagZ; i<this.numberOfFrequencies; i++){ + sumW28 += Math.abs(this.realZ[i]*Math.sqrt(this.omegas[i])); + sumW28 += Math.abs(this.imagZ[i]*Math.sqrt(this.omegas[i])); + } + this.initialEstimates[4] = sumW28/(2.0D*(this.numberOfFrequencies - indexMinImagZ)); + } + else{ + this.initialEstimates[1] = 3.0D/(this.initialEstimates[0]*geometricFreqMean); + this.initialEstimates[3] = this.initialEstimates[1]; + this.initialEstimates[5] = this.initialEstimates[1]; + for(int i=indexMinImagZ; i<this.numberOfFrequencies; i++){ + sumW28 += Math.abs(this.realZ[i]*Math.sqrt(this.omegas[i])); + sumW28 += Math.abs(this.imagZ[i]*Math.sqrt(this.omegas[i])); + } + this.initialEstimates[4] = sumW28/(2.0D*this.numberOfFrequencies); + } + break; + default: throw new IllegalArgumentException("Automatically calculated initial estimates are only presntly available for models 1 to 28"); + } + + // initial steps + this.initialSteps = new double[this.numberOfParameters]; + for(int i=0; i<this.numberOfParameters; i++)this.initialSteps[i] = Math.abs(this.initialEstimates[i])*0.1D; + + // check for zero step + for(int i=0; i<this.numberOfParameters; i++){ + if(this.initialSteps[i]==0.0D){ + if(this.parameterSymbols[i].trim().substring(0,1).equals("R"))this.initialSteps[i] = maxRealZ*0.01D; + if(this.parameterSymbols[i].trim().substring(0,1).equals("C"))this.initialSteps[i] = 0.01D/(imagBig*this.frequencies[bigIndex]); + if(this.parameterSymbols[i].trim().substring(0,1).equals("L"))this.initialSteps[i] = imagBig*0.01D/this.frequencies[bigIndex]; + if(this.parameterSymbols[i].trim().substring(0,1).equals("W"))this.initialSteps[i] = 0.01D/(imagBig*Math.sqrt(this.frequencies[bigIndex])); + if(this.parameterSymbols[i].trim().substring(0,2).equals("Fs"))this.initialSteps[i] = 0.01D/(imagBig*Math.sqrt(this.frequencies[bigIndex])); + if(this.parameterSymbols[i].trim().substring(0,2).equals("Fd"))this.initialSteps[i] = 0.05D; + if(this.parameterSymbols[i].trim().substring(0,2).equals("Qs"))this.initialSteps[i] = 0.01D/(imagBig*Math.sqrt(this.frequencies[bigIndex])); + if(this.parameterSymbols[i].trim().substring(0,2).equals("Qa"))this.initialSteps[i] = 0.005D; + } + } + + this.estimatesSet = true; + } + else{ + this.estimatesNeeded = true; + } + } + + // get the initial estimates + public double[] getInitialEstimates(){ + if(!this.estimatesSet)throw new IllegalArgumentException("No initial estimates have been entered or calculated"); + return this.initialEstimates; + } + + // get the model parameter symbols + public String[] getCircuitComponents(){ + return this.parameterSymbols; + } + + // REGRESSION + + // user addition of constraints + public void addNewConstraint(int parameter, int direction, double boundary){ + this.constraints.add(new Integer(parameter)); + this.constraints.add(new Integer(direction)); + this.constraints.add(new Double(boundary)); + this.numberOfAddedConstraints++; + this.constraintsAdded = true; + } + + public void addNewConstraint(String parameterSymbol, int direction, double boundary){ + if(this.numberOfParameters==0)throw new IllegalArgumentException("No model number or model parameters entered"); + int parameterNumber = -1; + for(int i=0; i<this.numberOfParameters; i++){ + if( this.parameterSymbols[i].trim().equals( parameterSymbol.trim() ) )parameterNumber = i; + } + if(parameterNumber == -1)throw new IllegalArgumentException("Parameter symbol, " + parameterSymbol + ", not found"); + + this.constraints.add(new Integer(parameterNumber)); + this.constraints.add(new Integer(direction)); + this.constraints.add(new Double(boundary)); + this.numberOfAddedConstraints++; + this.constraintsAdded = true; + } + + // remove default constraints on parameters + public void removeDefaultConstraints(){ + this.supressDefaultConstraints = true; + } + + // restore default constraints on parameters + public void restoreDefaultConstraints(){ + this.supressDefaultConstraints = false; + } + + // remove added constraints on parameters + public void removeAddedConstraints(){ + this.supressAddedConstraints = true; + this.constraintsAdded = false; + } + + // remove all constraints on parameters + public void removeAllConstraints(){ + this.supressDefaultConstraints = true; + this.supressAddedConstraints = true; + this.constraintsAdded = false; + } + + // reset maximum number of iterations + public void resetMaximumNumberOfIterations(int max){ + this.maximumIterations = max; + } + + // reset the regression tolerance + public void resetTolerance(double tol){ + this.tolerance = tol; + } + + // get the regression results as ArrayList + public ArrayList<Object> getRegressionResultsAsArrayList(){ + if(!this.regressionDone)this.regression(); + return this.results; + } + + // get the regression results as Vector + public Vector<Object> getRegressionResultsAsVector(){ + if(!this.regressionDone)this.regression(); + int n = this.results.size(); + Vector<Object> res = new Vector<Object>(n); + for(int i=0; i<n; i++)res.add(this.results.get(i)); + return res; + } + + // get the regression results as Vector + public Vector<Object> getRegressionResults(){ + return this.getRegressionResults(); + } + + // Set Regression data arrays + private void setRegressionArrays(){ + + this.xRegression = new double[this.numberOfFrequencies]; + this.yRegression = new double[2][this.numberOfFrequencies]; + if(this.weightsSet)this.wRegression = new double[2][this.numberOfFrequencies]; + + for(int i=0; i<this.numberOfFrequencies; i++){ + xRegression[i] = this.omegas[i]; + yRegression[0][i] = this.realZ[i]; + yRegression[1][i] = this.imagZ[i]; + } + + if(this.weightsSet){ + for(int i=0; i<this.numberOfFrequencies; i++){ + wRegression[0][i] = this.realZweights[i]; + wRegression[1][i] = this.imagZweights[i]; + } + } + } + + // fit the data to the chosen model + public ArrayList<Object> regression(){ + + // check data + this.degreesOfFreedom = this.numberOfFrequencies - this.numberOfParameters; + if(this.degreesOfFreedom<=0)throw new IllegalArgumentException("Degrees of freedom, " + this.degreesOfFreedom + ", are less than 1"); + if(!this.impedancesSet)throw new IllegalArgumentException("No impedances or voltages have been entered"); + + // check initial estimates have been provided + if(!this.estimatesSet && !this.userModelSet)this.setInitialEstimates(); + + // Set regression arrays + this.setRegressionArrays(); + + // store initial estimates and associated data + this.results = new ArrayList<Object>(); + this.results.add(new Integer(this.numberOfFrequencies)); + this.results.add(new Integer(this.numberOfParameters)); + this.results.add(new Integer(this.degreesOfFreedom)); + this.results.add(this.parameterSymbols); + this.results.add((double[])this.initialEstimates.clone()); + this.results.add((double[])this.initialSteps.clone()); + + // Enter regression data + if(this.weightsSet){ + this.enterData(xRegression, yRegression, wRegression); + } + else{ + this.enterData(xRegression, yRegression); + } + + // Create instance of regression function + if(this.userModelSet){ + ImpedSpecRegressionFunction2 function = new ImpedSpecRegressionFunction2(); + function.numberOfFrequencies = this.numberOfFrequencies; + function.isModel = this.userModel; + this.regressionFunction = function; + }else{ + ImpedSpecRegressionFunction1 function = new ImpedSpecRegressionFunction1(); + function.numberOfFrequencies = this.numberOfFrequencies; + function.modelNumber = this.modelNumber; + this.regressionFunction = function; + } + + // Enter user added constraints + int[] param = null; + int[] direct = null; + double[] bound = null; + if(this.constraintsAdded){ + param = new int[this.numberOfAddedConstraints]; + direct = new int[this.numberOfAddedConstraints]; + bound = new double[this.numberOfAddedConstraints]; + int index = 0; + for(int i=0; i<this.numberOfAddedConstraints; i++){ + int parameter = ((Integer)constraints.get(index)).intValue(); + param[i] = parameter; + index++; + int direction = ((Integer)constraints.get(index)).intValue(); + direct[i] = direction; + index++; + double boundary = ((Double)constraints.get(index)).doubleValue(); + bound[i] = boundary; + index++; + this.addConstraint(parameter, direction, boundary); + } + } + + // enter in-built constraints (if not set to be supressed) + if(!this.supressDefaultConstraints){ + + for(int i=0; i<this.numberOfParameters; i++){ + double lower = 0.0; + double upper = 1.0; + if(this.constraintsAdded){ + for(int j=0; j<this.numberOfAddedConstraints; j++){ + if(param[j]==i){ + if(direct[j]==1){ + upper = bound[j]; + } + else{ + lower = bound[j]; + } + } + } + } + this.addConstraint(i, -1, lower); + if(this.parameterSymbols[i].trim().substring(0,1).equals("Qa"))this.addConstraint(i, 1, upper); + } + } + + // perform regression + this.simplex2(this.regressionFunction, (double[])this.initialEstimates.clone(), (double[])this.initialSteps.clone(), this.tolerance, this.maximumIterations); + + // repeat regression with best estimates as new initial estimates + this.numberOfIterations1 = this.getNiter(); + double[] estimates = this.getCoeff(); + double[] steps = new double[this.numberOfParameters]; + for(int i=0; i<this.numberOfParameters; i++)steps[i] = Math.abs(estimates[i])*0.1D; + + this.simplex2(this.regressionFunction, estimates, steps, this.tolerance, this.maximumIterations); + + // store the regression results + this.bestEstimates = this.getCoeff(); + this.results.add(this.bestEstimates); + this.standardDeviations = this.getCoeffSd(); + this.results.add(this.standardDeviations); + this.coefficientsOfVariation = this.getCoeffVar(); + this.results.add(this.coefficientsOfVariation); + this.correlationCoefficients = this.getCorrCoeffMatrix(); + this.results.add(this.correlationCoefficients); + double[][] gradients = new double[this.numberOfParameters][2]; + if(this.getGrad()==null){ + for(int i=0; i<this.numberOfParameters; i++){ + this.preMinimumGradients[i] = Double.NaN; + this.postMinimumGradients[i] = Double.NaN; + } + } + else{ + gradients = this.getGrad(); + for(int i=0; i<this.numberOfParameters; i++){ + this.preMinimumGradients[i] = gradients[i][0]; + this.postMinimumGradients[i] = gradients[i][1]; + } + } + + this.results.add(this.preMinimumGradients); + this.results.add(this.postMinimumGradients); + this.sumOfSquares = this.getSumOfSquares(); + this.results.add(new Double(this.sumOfSquares)); + this.reducedSumOfSquares = this.sumOfSquares/this.degreesOfFreedom; + this.results.add(new Double(this.reducedSumOfSquares)); + if(this.weightsSet){ + this.chiSquare = this.getChiSquare(); + this.results.add(new Double(this.chiSquare)); + this.reducedChiSquare = this.getReducedChiSquare(); + this.results.add(new Double(this.reducedChiSquare)); + } + else{ + this.results.add(null); + this.results.add(null); + } + this.numberOfIterations2 = this.getNiter(); + this.results.add(new Integer(this.numberOfIterations1)); + this.results.add(new Integer(this.numberOfIterations2)); + this.results.add(new Integer(this.maximumIterations)); + this.results.add(this.dataEnteredType[this.dataEnteredTypePointer]); + + this.results.add(this.frequencies); + this.results.add(this.log10frequencies); + this.results.add(this.omegas); + this.results.add(this.log10omegas); + this.results.add(this.impedanceMagnitudes); + this.results.add(this.impedancePhasesRad); + this.results.add(this.impedancePhasesDeg); + this.results.add(this.impedances); + this.results.add(this.realZ); + this.results.add(this.imagZ); + + double[] calculatedY = this.getYcalc(); + for(int i=0; i<this.numberOfFrequencies; i++){ + this.calculatedRealZ[i] = calculatedY[i]; + this.calculatedImagZ[i] = calculatedY[i + this.numberOfFrequencies]; + } + this.results.add(this.calculatedRealZ); + this.results.add(this.calculatedImagZ); + + + double[] residuals = this.getResiduals(); + for(int i=0; i<this.numberOfFrequencies; i++){ + this.realZresiduals[i] = residuals[i]; + this.imagZresiduals[i] = residuals[i + this.numberOfFrequencies]; + } + this.results.add(this.realZresiduals); + this.results.add(this.imagZresiduals); + + if(this.weightsSet){ + switch(this.dataEnteredTypePointer){ + case 0: this.results.add(this.realVweights); + this.results.add(this.imagVweights); + break; + case 1: this.results.add(this.voltageWeights); + this.results.add(null); + break; + case 2: this.results.add(this.voltageMagnitudeWeights); + this.results.add(this.voltagePhaseWeightsRad); + break; + case 3: this.results.add(this.voltageMagnitudeWeights); + this.results.add(this.voltagePhaseWeightsDeg); + break; + case 4: this.results.add(this.realZweights); + this.results.add(this.imagZweights); + break; + case 5: this.results.add(this.impedanceWeights); + this.results.add(null); + break; + case 6: this.results.add(this.impedanceMagnitudeWeights); + this.results.add(this.impedancePhaseWeightsRad); + break; + case 7: this.results.add(this.impedanceMagnitudeWeights); + this.results.add(this.impedancePhaseWeightsDeg); + break; + default: this.results.add(null); + this.results.add(null); + } + this.results.add(this.realZweights); + this.results.add(this.imagZweights); + } + else{ + for(int i=0; i<4; i++)this.results.add(null); + } + + for(int i=0; i<this.numberOfFrequencies; i++){ + this.calculatedImpedances[i] = new Complex(this.calculatedRealZ[i], this.calculatedImagZ[i]); + this.calculatedImpedanceMagnitudes[i] = this.calculatedImpedances[i].abs(); + this.calculatedImpedancePhasesRad[i] = this.calculatedImpedances[i].arg(); + this.calculatedImpedancePhasesDeg[i] = Math.toDegrees(this.calculatedImpedancePhasesRad[i]); + } + this.results.add(this.calculatedImpedances); + this.results.add(this.calculatedImpedanceMagnitudes); + this.results.add(this.calculatedImpedancePhasesRad); + this.results.add(this.calculatedImpedancePhasesDeg); + + if(this.appliedVoltageSet && this.referenceSet){ + for(int i=0; i<this.numberOfFrequencies; i++){ + this.calculatedVoltages[i] = this.appliedVoltage.times(this.calculatedImpedances[i]).over(this.calculatedImpedances[i].plus(this.referenceImpedance)); + this.calculatedRealV[i] = this.calculatedVoltages[i].getReal(); + this.calculatedImagV[i] = this.calculatedVoltages[i].getImag(); + this.calculatedVoltageMagnitudes[i] = this.calculatedVoltages[i].abs(); + this.calculatedVoltagePhasesRad[i] = this.calculatedVoltages[i].arg(); + this.calculatedVoltagePhasesDeg[i] = Math.toDegrees(this.calculatedVoltagePhasesRad[i]); + } + this.results.add(this.calculatedVoltages); + this.results.add(this.calculatedRealV); + this.results.add(this.calculatedImagV); + this.results.add(this.calculatedVoltageMagnitudes); + this.results.add(this.calculatedVoltagePhasesRad); + this.results.add(this.calculatedVoltagePhasesDeg); + } + else{ + for(int i=0; i<6; i++)this.results.add(null); + } + + this.regressionDone = true; + + return this.results; + } + + // get the best estimates + public double[] getBestEstimates(){ + if(!this.regressionDone)this.regression(); + return this.bestEstimates; + } + + // get the best estimates standard deviations + public double[] getStandardDeviations(){ + if(!this.regressionDone)this.regression(); + return this.standardDeviations; + } + + // get the number of iterations taken in the first regression + public int getFirstNumberOfIterations(){ + return this.numberOfIterations1; + } + + // get the number of iterations taken in the second regression + public int getSecondNumberOfIterations(){ + return this.numberOfIterations2; + } + + // get the number of iterations taken + public double getTolerance(){ + return this.tolerance; + } + + // PLOT + + // Set linear option + public void setLinearPlot(){ + this.logOrLinear = false; + + } + + // Set log10 option + public void setLog10Plot(){ + this.logOrLinear = true; + } + + // Calculate line frequencies + private void calculateLineFrequencies(){ + double lowestFrequency = Fmath.minimum(this.frequencies); + double highestFrequency = Fmath.maximum(this.frequencies); + if(this.logOrLinear){ + double logLow = Fmath.log10(lowestFrequency); + double logHigh = Fmath.log10(highestFrequency); + double increment = (logHigh - logLow)/(this.numberOfLineFrequencies - 1); + this.lineFrequencies = new double[this.numberOfLineFrequencies]; + this.log10lineFrequencies = new double[this.numberOfLineFrequencies]; + this.log10lineFrequencies[0] = logLow; + this.log10lineFrequencies[this.numberOfLineFrequencies-1] = logHigh; + for(int i=1; i<this.numberOfLineFrequencies-1; i++)this.log10lineFrequencies[i] = this.log10lineFrequencies[i-1] + increment; + for(int i=0; i<this.numberOfLineFrequencies; i++)this.lineFrequencies[i] = Math.pow(10.0D, this.log10lineFrequencies[i]); + + } + else{ + double increment = (highestFrequency - lowestFrequency)/(this.numberOfLineFrequencies - 1); + this.lineFrequencies = new double[this.numberOfLineFrequencies]; + this.lineFrequencies[0] = lowestFrequency; + this.log10lineFrequencies = new double[this.numberOfLineFrequencies]; + this.lineFrequencies[this.numberOfLineFrequencies-1] = highestFrequency; + for(int i=1; i<this.numberOfLineFrequencies-1; i++)this.lineFrequencies[i] = this.lineFrequencies[i-1] + increment; + for(int i=0; i<this.numberOfLineFrequencies; i++)this.log10lineFrequencies[i] = Fmath.log10(this.lineFrequencies[i]); + } + } + + // Returns date and time + private String[] dateAndTime(){ + Date d = new Date(); + String[] ret = new String[2]; + ret[0] = DateFormat.getDateInstance().format(d); + ret[1] = DateFormat.getTimeInstance().format(d); + return ret; + } + + + // Display Cole-Cole Plot + public ArrayList<Object> plotColeCole(){ + String[] dAndT= this.dateAndTime(); + String graphTitle1 = "ImpedSpecRegression program: Cole - Cole plot [" + dAndT[0] + " " + dAndT[1] + "]"; + String graphTitle2 = this.regressionTitle; + + if(!this.regressionDone)this.regression(); + + this.calculateLineFrequencies(); + + double[][] data = PlotGraph.data(2, this.numberOfLineFrequencies); + + for(int i=0; i<this.numberOfFrequencies; i++){ + data[0][i] = this.realZ[this.numberOfFrequencies - i - 1]; + data[1][i] = -this.imagZ[this.numberOfFrequencies - i - 1]; + } + + if(this.userModelSet){ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = userModel.modelImpedance(this.bestEstimates, this.lineFrequencies[this.numberOfLineFrequencies - i - 1]*2.0D*Math.PI).getReal(); + data[3][i] = -userModel.modelImpedance(this.bestEstimates, this.lineFrequencies[this.numberOfLineFrequencies - i - 1]*2.0D*Math.PI).getImag(); + } + } + else{ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = Impedance.modelImpedance(this.bestEstimates, this.lineFrequencies[this.numberOfLineFrequencies - i - 1]*2.0D*Math.PI, this.modelNumber).getReal(); + data[3][i] = -Impedance.modelImpedance(this.bestEstimates, this.lineFrequencies[this.numberOfLineFrequencies - i - 1]*2.0D*Math.PI, this.modelNumber).getImag(); + } + } + + PlotGraph pg = new PlotGraph(data); + int[] lineOpt = {0, 3}; + pg.setLine(lineOpt); + int[] pointOpt = {1, 0}; + pg.setPoint(pointOpt); + pg.setGraphTitle(graphTitle1); + pg.setGraphTitle2(graphTitle2); + pg.setXaxisLegend("Real[Impedance / ohms]"); + pg.setYaxisLegend("-Imag[Impedance / ohms]"); + pg.plot(); + + return this.results; + } + + // Plot impedance magnitude versus frequency + public ArrayList<Object> plotImpedanceMagnitudes(){ + + String[] dAndT= this.dateAndTime(); + String graphTitle1 = "ImpedSpecRegression program: Impedance magnitude versus frequency plot [" + dAndT[0] + " " + dAndT[1] + "]"; + String graphTitle2 = this.regressionTitle; + + if(!this.regressionDone)this.regression(); + + this.calculateLineFrequencies(); + + // Magnitude versus frequency + double[][] data = PlotGraph.data(2, this.numberOfLineFrequencies); + + if(this.logOrLinear){ + for(int i=0; i<this.numberOfFrequencies; i++){ + data[0][i] = this.log10frequencies[i]; + data[1][i] = this.impedanceMagnitudes[i]; + } + } + else{ + for(int i=0; i<this.numberOfFrequencies; i++){ + data[0][i] = this.frequencies[i]; + data[1][i] = this.impedanceMagnitudes[i]; + } + } + + if(this.logOrLinear){ + if(this.userModelSet){ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.log10lineFrequencies[i]; + Complex imped = userModel.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI); + data[3][i] = imped.abs(); + } + } + else{ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.log10lineFrequencies[i]; + Complex imped = Impedance.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI, this.modelNumber); + data[3][i] = imped.abs(); + } + } + } + else{ + if(this.userModelSet){ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.lineFrequencies[i]; + Complex imped = userModel.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI); + data[3][i] = imped.abs(); + } + } + else{ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.lineFrequencies[i]; + Complex imped = Impedance.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI, this.modelNumber); + data[3][i] = imped.abs(); + } + } + } + + PlotGraph pg = new PlotGraph(data); + int[] lineOpt = {0, 3}; + pg.setLine(lineOpt); + int[] pointOpt = {1, 0}; + pg.setPoint(pointOpt); + pg.setGraphTitle(graphTitle1); + pg.setGraphTitle2(graphTitle2); + if(this.logOrLinear){ + pg.setXaxisLegend("Log10[Frequency / Hz]"); + } + else{ + pg.setXaxisLegend("Frequency / Hz"); + } + pg.setYaxisLegend("Impedance Magnitude"); + pg.plot(); + + return this.results; + } + + // Plot impedance phase versus frequency + public ArrayList<Object> plotImpedancePhases(){ + + String[] dAndT= this.dateAndTime(); + String graphTitle1 = "ImpedSpecRegression program: Impedance phase versus frequency plot [" + dAndT[0] + " " + dAndT[1] + "]"; + String graphTitle2 = this.regressionTitle; + + if(!this.regressionDone)this.regression(); + + this.calculateLineFrequencies(); + + // Magnitude versus frequency + double[][] data = PlotGraph.data(2, this.numberOfLineFrequencies); + + if(this.logOrLinear){ + for(int i=0; i<this.numberOfFrequencies; i++){ + data[0][i] = this.log10frequencies[i]; + data[1][i] = this.impedancePhasesDeg[i]; + } + } + else{ + for(int i=0; i<this.numberOfFrequencies; i++){ + data[0][i] = this.frequencies[i]; + data[1][i] = this.impedancePhasesDeg[i]; + } + } + + if(this.logOrLinear){ + if(this.userModelSet){ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.log10lineFrequencies[i]; + Complex imped = userModel.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI); + data[3][i] = Math.toDegrees(imped.arg()); + } + } + else{ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.log10lineFrequencies[i]; + Complex imped = Impedance.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI, this.modelNumber); + data[3][i] = Math.toDegrees(imped.arg()); + } + } + } + else{ + if(this.userModelSet){ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.lineFrequencies[i]; + Complex imped = userModel.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI); + data[3][i] = Math.toDegrees(imped.arg()); + } + } + else{ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.lineFrequencies[i]; + Complex imped = Impedance.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI, this.modelNumber); + data[3][i] = Math.toDegrees(imped.arg()); + } + } + } + + PlotGraph pg = new PlotGraph(data); + int[] lineOpt = {0, 3}; + pg.setLine(lineOpt); + int[] pointOpt = {1, 0}; + pg.setPoint(pointOpt); + pg.setGraphTitle(graphTitle1); + pg.setGraphTitle2(graphTitle2); + if(this.logOrLinear){ + pg.setXaxisLegend("Log10[Frequency / Hz]"); + } + else{ + pg.setXaxisLegend("Frequency / Hz"); + } + pg.setYaxisLegend("Impedance Phase / degrees"); + pg.plot(); + + return this.results; + } + + + // Plot voltage magnitude versus frequency + public ArrayList<Object> plotVoltageMagnitudes(){ + + if(!this.regressionDone)this.regression(); + + if(this.referenceSet && this.appliedVoltageSet){ + String[] dAndT= this.dateAndTime(); + String graphTitle1 = "ImpedSpecRegression program: Voltage magnitude versus frequency plot [" + dAndT[0] + " " + dAndT[1] + "]"; + String graphTitle2 = this.regressionTitle; + + this.calculateLineFrequencies(); + + double[][] data = PlotGraph.data(2, this.numberOfLineFrequencies); + + if(this.logOrLinear){ + for(int i=0; i<this.numberOfFrequencies; i++){ + data[0][i] = this.log10frequencies[i]; + data[1][i] = this.voltageMagnitudes[i]; + } + } + else{ + for(int i=0; i<this.numberOfFrequencies; i++){ + data[0][i] = this.frequencies[i]; + data[1][i] = this.voltageMagnitudes[i]; + } + } + + if(this.logOrLinear){ + if(this.userModelSet){ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.log10lineFrequencies[i]; + Complex imped = userModel.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI); + Complex volt = imped.times(this.appliedVoltage).over(this.referenceImpedance.plus(imped)); + data[3][i] = volt.abs(); + } + } + else{ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.log10lineFrequencies[i]; + Complex imped = Impedance.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI, this.modelNumber); + Complex volt = imped.times(this.appliedVoltage).over(this.referenceImpedance.plus(imped)); + data[3][i] = volt.abs(); + } + } + } + else{ + if(this.userModelSet){ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.lineFrequencies[i]; + Complex imped = userModel.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI); + Complex volt = imped.times(this.appliedVoltage).over(this.referenceImpedance.plus(imped)); + data[3][i] = volt.abs(); + } + } + else{ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.lineFrequencies[i]; + Complex imped = Impedance.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI, this.modelNumber); + Complex volt = imped.times(this.appliedVoltage).over(this.referenceImpedance.plus(imped)); + data[3][i] = volt.abs(); + } + } + } + + PlotGraph pg = new PlotGraph(data); + int[] lineOpt = {0, 3}; + pg.setLine(lineOpt); + int[] pointOpt = {1, 0}; + pg.setPoint(pointOpt); + pg.setGraphTitle(graphTitle1); + pg.setGraphTitle2(graphTitle2); + if(this.logOrLinear){ + pg.setXaxisLegend("Log10[Frequency / Hz]"); + } + else{ + pg.setXaxisLegend("Frequency / Hz"); + } + pg.setYaxisLegend("Voltage Magnitude"); + pg.plot(); + } + else{ + System.out.println("The voltage magnitudes cannot be plotted as no reference impedance or applied voltage has been entered"); + } + + return this.results; + } + + // Plot voltage phase versus frequency + public ArrayList<Object> plotVoltagePhases(){ + + if(!this.regressionDone)this.regression(); + + if(this.referenceSet && this.appliedVoltageSet){ + String[] dAndT= this.dateAndTime(); + String graphTitle1 = "ImpedSpecRegression program: Voltage phase versus frequency plot [" + dAndT[0] + " " + dAndT[1] + "]"; + String graphTitle2 = this.regressionTitle; + + this.calculateLineFrequencies(); + + double[][] data = PlotGraph.data(2, this.numberOfLineFrequencies); + + if(this.logOrLinear){ + for(int i=0; i<this.numberOfFrequencies; i++){ + data[0][i] = this.log10frequencies[i]; + data[1][i] = this.voltagePhasesDeg[i]; + } + } + else{ + for(int i=0; i<this.numberOfFrequencies; i++){ + data[0][i] = this.frequencies[i]; + data[1][i] = this.voltagePhasesDeg[i]; + } + } + + if(this.logOrLinear){ + if(this.userModelSet){ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.log10lineFrequencies[i]; + Complex imped = userModel.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI); + Complex volt = imped.times(this.appliedVoltage).over(this.referenceImpedance.plus(imped)); + data[3][i] = Math.toDegrees(volt.arg()); + } + } + else{ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.log10lineFrequencies[i]; + Complex imped = Impedance.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI, this.modelNumber); + Complex volt = imped.times(this.appliedVoltage).over(this.referenceImpedance.plus(imped)); + data[3][i] = Math.toDegrees(volt.arg()); + } + } + } + else{ + if(this.userModelSet){ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.lineFrequencies[i]; + Complex imped = userModel.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI); + Complex volt = imped.times(this.appliedVoltage).over(this.referenceImpedance.plus(imped)); + data[3][i] = Math.toDegrees(volt.arg()); + } + } + else{ + for(int i=0; i<this.numberOfLineFrequencies; i++){ + data[2][i] = this.lineFrequencies[i]; + Complex imped = Impedance.modelImpedance(this.bestEstimates, this.lineFrequencies[i]*2.0D*Math.PI, this.modelNumber); + Complex volt = imped.times(this.appliedVoltage).over(this.referenceImpedance.plus(imped)); + data[3][i] = Math.toDegrees(volt.arg()); + } + } + } + + PlotGraph pg = new PlotGraph(data); + int[] lineOpt = {0, 3}; + pg.setLine(lineOpt); + int[] pointOpt = {1, 0}; + pg.setPoint(pointOpt); + pg.setGraphTitle(graphTitle1); + pg.setGraphTitle2(graphTitle2); + if(this.logOrLinear){ + pg.setXaxisLegend("Log10[Frequency / Hz]"); + } + else{ + pg.setXaxisLegend("Frequency / Hz"); + } + pg.setYaxisLegend("Voltage Phases / degrees"); + pg.plot(); + } + else{ + System.out.println("The voltage magnitudes cannot be plotted as no reference impedance or applied voltage has been entered"); + } + + return this.results; + } + + // PRINT + + // Print regression results to text file + public ArrayList<Object> printToTextFile(){ + String fileName = "ImpedSpecRegressionOutput.txt"; + this.fileType = true; + return this.printToTextFile(fileName); + } + + // Print regression results to text file + public ArrayList<Object> printToTextFile(String fileName){ + + if(!this.regressionDone)regression(); + + int field = 11; // output field length + int trunc = 4; // truncation length + + // Check extension + fileName = fileName.trim(); + int dotPosition = fileName.indexOf('.'); + if(dotPosition==-1)fileName += ".txt"; + + // instantiate a FileOutput + FileOutput fout = null; + if(this.fileType){ + fout = new FileOutput(fileName, 'n'); + } + else{ + fout = new FileOutput(fileName); + } + + // print header + fout.println("ImpedSpecRegression Program Output File: " + this.regressionTitle); + fout.dateAndTimeln(fileName); + fout.println(); + if(this.modelSet){ + fout.println("Circuit - model number " + this.modelNumber); + } + else{ + fout.println("Circuit supplied by the user"); + } + fout.println(); + + + // print circuit parameters + fout.println("Circuit Parameters"); + fout.println("Best Estimates"); + + fout.print("Parameter", field); + fout.print("Best", field); + fout.print("Standard", field); + fout.print("Coeff. of", field); + fout.print("Pre-", field); + fout.println("Post-"); + + fout.print(" ", field); + fout.print("estimate", field); + fout.print("deviation", field); + fout.print("variation", field); + fout.print("gradient", field); + fout.println("gradient"); + + for(int i=0; i<this.numberOfParameters; i++){ + fout.print(this.parameterSymbols[i], field); + fout.print(Fmath.truncate(this.bestEstimates[i], trunc), field); + fout.print(Fmath.truncate(this.standardDeviations[i], trunc), field); + fout.print(Fmath.truncate(this.coefficientsOfVariation[i], trunc), field); + fout.print(Fmath.truncate(this.preMinimumGradients[i], trunc), field); + fout.println(Fmath.truncate(this.postMinimumGradients[i], trunc)); + } + fout.println(); + + fout.println("Initial Estimates"); + + fout.print("Parameter", field); + fout.print("Initial", field); + fout.println("initial"); + + fout.print(" ", field); + fout.print("estimate", field); + fout.println("step size"); + + for(int i=0; i<this.numberOfParameters; i++){ + fout.print(this.parameterSymbols[i], field); + fout.print(Fmath.truncate(this.initialEstimates[i], trunc), field); + fout.println(Fmath.truncate(this.initialSteps[i], trunc)); + } + fout.println(); + + // Print summary of regression statistics + fout.println("Sum of squares of the Real[Z] and Imag[Z] residuals: " + Fmath.truncate(this.sumOfSquares, trunc)); + fout.println("Reduced sum of squares of the Real[Z] and Imag[Z] residuals: " + Fmath.truncate(this.sumOfSquares/this.degreesOfFreedom, trunc)); + fout.println("Degrees of freedom: " + this.degreesOfFreedom); + if(this.weightsSet){ + fout.println("Chi square: " + Fmath.truncate(this.chiSquare, trunc)); + fout.println("Reduced chi square: " + Fmath.truncate(this.reducedChiSquare, trunc)); + } + fout.println("Number of iterations taken in the first regression: " + this.numberOfIterations1); + fout.println("Number of iterations taken in the second regression: " + this.numberOfIterations2); + fout.println("Maximum number of iterations allowed in each regression: " + this.maximumIterations); + fout.println(); + + // print aplied voltage and reference impedance if entered + if(this.appliedVoltageSet)fout.println("Applied voltage: " + this.appliedVoltage.getReal()); + if(this.referenceSet)fout.println("Reference impedance: " + this.referenceImpedance); + fout.println(); + + // Print impedance data for each frequency + field=14; + fout.println("Fitted and entered data [frequencies, calculated impedances, data as entered]"); + fout.print("Entered data type: "); + fout.println(dataEnteredType[dataEnteredTypePointer]); + fout.println(); + + fout.print("Frequency", field); + fout.print("Experimental", field); + fout.print("Calculated", field); + fout.print("Experimental", field); + fout.print("Calculated", field); + + switch(this.dataEnteredTypePointer){ + case 0: fout.print("Real", field); + fout.print("Imag", field); + break; + case 1: fout.print("Complex", field); + break; + case 2: fout.print("Magnitude", field); + fout.print("Phase (rad)", field); + break; + case 3: fout.print("Magnitude", field); + fout.print("Phase (deg)", field); + break; + case 4: fout.print("Real", field); + fout.print("Imag", field); + break; + case 5: fout.print("Complex", field); + break; + case 6: fout.print("Magnitude", field); + fout.print("Phase (rad)", field); + break; + case 7: fout.print("Magnitude", field); + fout.print("Phase (deg)", field); + break; + } + fout.println(); + + fout.print("Frequency", field); + fout.print("Real[Z]", field); + fout.print("Real[Z]", field); + fout.print("Imag[Z]", field); + fout.print("Imag[Z]", field); + switch(this.dataEnteredTypePointer){ + case 0: fout.print("[voltage]", field); + fout.print("[voltage]", field); + break; + case 1: fout.print("voltage", field); + break; + case 2: fout.print("[voltage]", field); + fout.print("[voltage]", field); + break; + case 3: fout.print("[voltage]", field); + fout.print("[voltage]", field); + break; + case 4: fout.print("[impedance]", field); + fout.print("[impedance]", field); + break; + case 5: fout.print("impedance", field); + break; + case 6: fout.print("[impedance]", field); + fout.print("[impedance]", field); + break; + case 7: fout.print("[impedance]", field); + fout.print("[impedance]", field); + break; + } + fout.println(); + + for(int i=0; i<this.numberOfFrequencies; i++){ + fout.print(Fmath.truncate(this.frequencies[i], trunc), field); + fout.print(Fmath.truncate(this.realZ[i], trunc), field); + fout.print(Fmath.truncate(this.calculatedRealZ[i], trunc), field); + fout.print(Fmath.truncate(this.imagZ[i], trunc), field); + fout.print(Fmath.truncate(this.calculatedImagZ[i], trunc),field); + + switch(this.dataEnteredTypePointer){ + case 0: fout.print(Fmath.truncate(this.realV[i], trunc), field); + fout.print(Fmath.truncate(this.imagV[i], trunc), field); + break; + case 1: fout.print(Complex.truncate(this.voltages[i], trunc), field); + break; + case 2: fout.print(Fmath.truncate(this.voltageMagnitudes[i], trunc), field); + fout.print(Fmath.truncate(this.voltagePhasesRad[i], trunc), field); + break; + case 3: fout.print(Fmath.truncate(this.voltageMagnitudes[i], trunc), field); + fout.print(Fmath.truncate(this.voltagePhasesDeg[i], trunc), field); + break; + case 4: fout.print(Fmath.truncate(this.realZ[i], trunc), field); + fout.print(Fmath.truncate(this.imagZ[i], trunc), field); + break; + case 5: fout.print(Complex.truncate(this.impedances[i], trunc), field); + break; + case 6: fout.print(Fmath.truncate(this.impedanceMagnitudes[i], trunc), field); + fout.print(Fmath.truncate(this.impedancePhasesRad[i], trunc), field); + break; + case 7: fout.print(Fmath.truncate(this.impedanceMagnitudes[i], trunc), field); + fout.print(Fmath.truncate(this.impedancePhasesDeg[i], trunc), field); + break; + } + fout.println(); + } + fout.close(); + + return this.results; + } + + + // Print regression results to a .xls (MS Excel) file + public ArrayList<Object> printToExcelFile(){ + String fileName = "ImpedSpecRegressionOutput.txt"; + this.fileType = true; + return this.printToExcelFile(fileName); + } + + // Print regression results to a .xls (MS Excel) file + public ArrayList<Object> printToExcelFile(String fileName){ + + if(!this.regressionDone)regression(); + + int field = 11; // output field length + int trunc = 4; // truncation length + + // Check extension + fileName = fileName.trim(); + int dotPosition = fileName.indexOf('.'); + if(dotPosition==-1){ + fileName += ".xls"; + } + else{ + fileName = fileName.substring(0, dotPosition) + ".xls"; + } + + // instantiate a FileOutput + FileOutput fout = null; + if(this.fileType){ + fout = new FileOutput(fileName, 'n'); + } + else{ + fout = new FileOutput(fileName); + } + + // print header + fout.println("ImpedSpecRegression Program Output File: " + this.regressionTitle); + fout.dateAndTimeln(fileName); + fout.println(); + if(this.modelSet){ + fout.println("Circuit - model number " + this.modelNumber); + } + else{ + fout.println("Circuit supplied by the user"); + } + fout.println(); + + + // print circuit parameters + fout.println("Circuit Parameters"); + fout.println("Best Estimates"); + + fout.printtab("Parameter", field); + fout.printtab("Best", field); + fout.printtab("Standard", field); + fout.printtab("Coeff. of", field); + fout.printtab("Pre-", field); + fout.println("Post-"); + + fout.printtab(" ", field); + fout.printtab("estimate", field); + fout.printtab("deviation", field); + fout.printtab("variation", field); + fout.printtab("gradient", field); + fout.println("gradient"); + + for(int i=0; i<this.numberOfParameters; i++){ + fout.printtab(this.parameterSymbols[i], field); + fout.printtab(Fmath.truncate(this.bestEstimates[i], trunc), field); + fout.printtab(Fmath.truncate(this.standardDeviations[i], trunc), field); + fout.printtab(Fmath.truncate(this.coefficientsOfVariation[i], trunc), field); + fout.printtab(Fmath.truncate(this.preMinimumGradients[i], trunc), field); + fout.println(Fmath.truncate(this.postMinimumGradients[i], trunc)); + } + fout.println(); + + fout.println("Initial Estimates"); + + fout.printtab("Parameter", field); + fout.printtab("Initial", field); + fout.println("initial"); + + fout.printtab(" ", field); + fout.printtab("estimate", field); + fout.println("step size"); + + for(int i=0; i<this.numberOfParameters; i++){ + fout.printtab(this.parameterSymbols[i], field); + fout.printtab(Fmath.truncate(this.initialEstimates[i], trunc), field); + fout.println(Fmath.truncate(this.initialSteps[i], trunc)); + } + fout.println(); + + // Print summary of regression statistics + fout.println("Sum of squares of the Real[Z] and Imag[z] residuals: " + Fmath.truncate(this.sumOfSquares, trunc)); + fout.println("Reduced sum of squares of the Real[Z] and Imag[z] residuals: " + Fmath.truncate(this.sumOfSquares/this.degreesOfFreedom, trunc)); + fout.println("Degrees of freedom: " + this.degreesOfFreedom); + if(this.weightsSet){ + fout.println("Chi square: " + Fmath.truncate(this.chiSquare, trunc)); + fout.println("Reduced chi square: " + Fmath.truncate(this.reducedChiSquare, trunc)); + } + fout.println("Number of iterations taken in the first regression: " + this.numberOfIterations1); + fout.println("Number of iterations taken in the second regression: " + this.numberOfIterations2); + fout.println("Maximum number of iterations allowed in each regression: " + this.maximumIterations); + fout.println(); + + // Print impedance data for each frequency + field=14; + fout.println("Fitted and entered data [frequencies, calculated impedances, data as entered]"); + fout.print("Entered data type: "); + fout.println(dataEnteredType[dataEnteredTypePointer]); + fout.println(); + + fout.printtab("Frequency", field); + fout.printtab("Experimental", field); + fout.printtab("Calculated", field); + fout.printtab("Experimental", field); + fout.printtab("Calculated", field); + + switch(this.dataEnteredTypePointer){ + case 0: fout.printtab("Real", field); + fout.printtab("Imag", field); + break; + case 1: fout.printtab("Complex", field); + break; + case 2: fout.printtab("Magnitude", field); + fout.printtab("Phase (rad)", field); + break; + case 3: fout.printtab("Magnitude", field); + fout.printtab("Phase (deg)", field); + break; + case 4: fout.printtab("Real", field); + fout.printtab("Imag", field); + break; + case 5: fout.printtab("Complex", field); + break; + case 6: fout.printtab("Magnitude", field); + fout.printtab("Phase (rad)", field); + break; + case 7: fout.printtab("Magnitude", field); + fout.printtab("Phase (deg)", field); + break; + } + fout.println(); + + fout.printtab("Frequency", field); + fout.printtab("Real[Z]", field); + fout.printtab("Real[Z]", field); + fout.printtab("Imag[Z]", field); + fout.printtab("Imag[Z]", field); + switch(this.dataEnteredTypePointer){ + case 0: fout.printtab("[voltage]", field); + fout.printtab("[voltage]", field); + break; + case 1: fout.printtab("voltage", field); + break; + case 2: fout.printtab("[voltage]", field); + fout.printtab("[voltage]", field); + break; + case 3: fout.printtab("[voltage]", field); + fout.printtab("[voltage]", field); + break; + case 4: fout.printtab("[impedance]", field); + fout.printtab("[impedance]", field); + break; + case 5: fout.printtab("impedance", field); + break; + case 6: fout.printtab("[impedance]", field); + fout.printtab("[impedance]", field); + break; + case 7: fout.printtab("[impedance]", field); + fout.printtab("[impedance]", field); + break; + } + fout.println(); + + for(int i=0; i<this.numberOfFrequencies; i++){ + fout.printtab(Fmath.truncate(this.frequencies[i], trunc), field); + fout.printtab(Fmath.truncate(this.realZ[i], trunc), field); + fout.printtab(Fmath.truncate(this.calculatedRealZ[i], trunc), field); + fout.printtab(Fmath.truncate(this.imagZ[i], trunc), field); + fout.printtab(Fmath.truncate(this.calculatedImagZ[i], trunc),field); + + switch(this.dataEnteredTypePointer){ + case 0: fout.printtab(Fmath.truncate(this.realV[i], trunc), field); + fout.printtab(Fmath.truncate(this.imagV[i], trunc), field); + break; + case 1: fout.printtab(Complex.truncate(this.voltages[i], trunc), field); + break; + case 2: fout.printtab(Fmath.truncate(this.voltageMagnitudes[i], trunc), field); + fout.printtab(Fmath.truncate(this.voltagePhasesRad[i], trunc), field); + break; + case 3: fout.printtab(Fmath.truncate(this.voltageMagnitudes[i], trunc), field); + fout.printtab(Fmath.truncate(this.voltagePhasesDeg[i], trunc), field); + break; + case 4: fout.printtab(Fmath.truncate(this.realZ[i], trunc), field); + fout.printtab(Fmath.truncate(this.imagZ[i], trunc), field); + break; + case 5: fout.printtab(Complex.truncate(this.impedances[i], trunc), field); + break; + case 6: fout.printtab(Fmath.truncate(this.impedanceMagnitudes[i], trunc), field); + fout.printtab(Fmath.truncate(this.impedancePhasesRad[i], trunc), field); + break; + case 7: fout.printtab(Fmath.truncate(this.impedanceMagnitudes[i], trunc), field); + fout.printtab(Fmath.truncate(this.impedancePhasesDeg[i], trunc), field); + break; + + } + fout.println(); + } + + // close file + fout.close(); + + return this.results; + } +} + + + + diff --git a/src/main/java/flanagan/circuits/ImpedSpecRegressionFunction1.java b/src/main/java/flanagan/circuits/ImpedSpecRegressionFunction1.java new file mode 100755 index 0000000000000000000000000000000000000000..766ab4c4793601c49776416386c8f9bad1f88619 --- /dev/null +++ b/src/main/java/flanagan/circuits/ImpedSpecRegressionFunction1.java @@ -0,0 +1,58 @@ +/* Class ImpedSpecRegressionFunction1 +* +* This class acts as a container for a precompiled circuit model, +* selected from class Impedance, for the class ImpedSpecRegression +* which contains the non-linear regression procedures for fitting impedance +* spectroscopy and electrochemical impedance spectroscopy data to a circuit model. +* +* This class implements RegressionFunction2 +* The user supplied circuit model requires the interface ImpedSpecModel +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: May 2007 +* +* DOCUMENTATION: +* See Michael T Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* http://www.ee.ucl.ac.uk/~mflanaga/java/ImpedSpecSimulation.html +* +* Copyright (c) May 2007 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +****************************************************************************************/ + +package flanagan.circuits; + +import flanagan.io.*; +import flanagan.complex.Complex; +import flanagan.analysis.RegressionFunction2; + +public class ImpedSpecRegressionFunction1 extends Impedance implements RegressionFunction2{ + + public int numberOfFrequencies = 0; // number of frequencies + public int modelNumber = 0; // Impedance class model number + + public double function(double[] parameters, double[] omega, int pointN){ + + Complex zVal = Impedance.modelImpedance(parameters, omega[0], this.modelNumber); // call impedance calculation method + + if(pointN<this.numberOfFrequencies){ + return zVal.getReal(); + } + else{ + return zVal.getImag(); + } + } +} + + diff --git a/src/main/java/flanagan/circuits/ImpedSpecRegressionFunction2.java b/src/main/java/flanagan/circuits/ImpedSpecRegressionFunction2.java new file mode 100755 index 0000000000000000000000000000000000000000..c0e07f46d42a21d3172860983c727bc12d15fa2f --- /dev/null +++ b/src/main/java/flanagan/circuits/ImpedSpecRegressionFunction2.java @@ -0,0 +1,59 @@ +/* Class ImpedSpecRegressionFunction2 +* +* This class acts as a container for the user supplied regression function, +* via the interface ImpedSpecModel, for the class ImpedSpecRegression +* which contains the non-linear regression procedures for fitting impedance +* spectroscopy and electrochemical impedance spectroscopy +* data to a circuit model. +* +* This class implements RegressionFunction2 +* The user supplied circuit model requires the interface ImpedSpecModel +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: May 2007 +* +* DOCUMENTATION: +* See Michael T Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* http://www.ee.ucl.ac.uk/~mflanaga/java/ImpedSpecSimulation.html +* +* Copyright (c) May 2007 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +****************************************************************************************/ + +package flanagan.circuits; + +import flanagan.io.*; +import flanagan.complex.Complex; +import flanagan.analysis.RegressionFunction2; + +public class ImpedSpecRegressionFunction2 implements RegressionFunction2{ + + public int numberOfFrequencies = 0; // number of frequencies + protected ImpedSpecModel isModel = null; // ImpedSpecModel containing the regression function + + public double function(double[] parameters, double[] omega, int pointN){ + + Complex zVal = isModel.modelImpedance(parameters, omega[0]); // call impedance calculation method + + if(pointN<this.numberOfFrequencies){ + return zVal.getReal(); + } + else{ + return zVal.getImag(); + } + } +} + + diff --git a/src/main/java/flanagan/circuits/ImpedSpecSimulation.java b/src/main/java/flanagan/circuits/ImpedSpecSimulation.java new file mode 100755 index 0000000000000000000000000000000000000000..8c197e86cf228bf049935fbdf96004b67318532c --- /dev/null +++ b/src/main/java/flanagan/circuits/ImpedSpecSimulation.java @@ -0,0 +1,1152 @@ +/* Class ImpedSpecSimulation +* +* Calculates and displays the impedance spectra +* for a user supplied circuit or for one of a +* range of class supplied circuits +* +* User supplied circuit models require the interface ImpedSpecModel +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 25 May 2007 (Derived from impedance spectroscopy programs, 2004 - 2007) +* UPDATED: 1 June 2007, 7 June 2007, 8 June 2007, 5 July 2008 +* +* DOCUMENTATION: +* See Michael T Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* http://www.ee.ucl.ac.uk/~mflanaga/java/ImpedSpecSimulation.html +* +* Copyright (c) May 2007 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +****************************************************************************************/ + +package flanagan.circuits; + +import flanagan.circuits.Impedance; +import flanagan.io.*; +import flanagan.complex.Complex; +import flanagan.math.Fmath; +import flanagan.plot.*; + +import java.text.*; +import java.util.*; + + +public class ImpedSpecSimulation{ + + private double lowestFrequency = 0.0D; // lowest frequency (Hz) + private double lowestOmega = 0.0D; // lowest frequency (radians) + private boolean lowestSet = false; // = true when lowest frequency entered + private double highestFrequency = 0.0D; // highest frequency (Hz) + private double highestOmega = 0.0D; // highest frequency (radians) + private boolean highestSet = false; // = true when highest frequency entered + private boolean logOrLinear = true; // = true; log plot + // = false; linear plot + private double increment = 0.0D; // plotting increment + // if logOrLinear = true - log10[Hz] increment + // if logOrLinear = false - linear [Hz] increment + private double[] frequencies = null; // frequencies [Hz] + private double[] omegas = null; // radial frequencies + private double[] log10frequencies = null; // log10[frequencies/Hz] + private double[] log10omegas = null; // log10[radial frequencies] + + private int numberOfFrequencies = 800; // number of points in the simulation + private boolean numberSet = true; // = true when number of points entered + private boolean frequenciesSet = false; // = true when frequencies entered + + private int modelNumber = 0; // model number + private double[] parameters = null; // model parameters + private int numberOfParameters = 0; // number of model parameters + private String[] modelParameterSymbols = null; // model parameter symbols + private boolean parametersSet = false; // = true when parameters entered + private boolean modelSet = false; // = true when a model number is set + + private Complex[] impedances = null; // impedances + private double[] magnitudesZ = null; // magnitudes + private double[] phasesRadZ = null; // impedance phases [radians] + private double[] phasesDegZ = null; // impedance phases [degrees] + private double[] realZ = null; // real part of the impedance + private double[] imagZ = null; // imaginary part of the impedance + + private boolean impedancesSet = false; // = true when impedances calculated + + private Complex[] voltages = null; // voltages across test circuit + private double[] magnitudesV = null; // voltage magnitudes + private double[] phasesRadV = null; // voltage phases [radians] + private double[] phasesDegV = null; // voltage phases [degrees] + private double[] realV = null; // real part of the voltage + private double[] imagV = null; // imaginary part of the voltage + + private ImpedSpecModel userModel = null; // user supplied model + + private String simulationTitle = null; // Title for output graphs and text file + private boolean fileType = false; // = true if 'n' number to be added to file name + + private Complex appliedVoltage = null; // magnitude of the applied voltage as complex + private boolean voltageSet = false; // = true when applied voltage entered + + private Complex referenceImpedance = null; // reference impedance + private boolean referenceSet = false; // = true when reference impedance entered + + + // Constructor + public ImpedSpecSimulation(){ + this.simulationTitle = " "; + } + + // Constructor + public ImpedSpecSimulation(String simulationTitle){ + this.simulationTitle = simulationTitle; + } + + // Set scan range in Hz + public void setScanRangeHz(double low, double high){ + this.lowestFrequency = low; + this.lowestOmega = 2.0D*Math.PI*low; + this.highestFrequency = high; + this.highestOmega = 2.0D*Math.PI*high; + this.calculateFrequencies(); + } + + // Set scan range in radians + public void setScanRangeRadians(double low, double high){ + this.lowestFrequency = low/(2.0D*Math.PI); + this.lowestOmega = low; + this.highestFrequency = high/(2.0D*Math.PI); + this.highestOmega = high; + this.calculateFrequencies(); + } + + // Set lowest frequency in Hz + public void setLowFrequency(double low){ + this.lowestFrequency = low; + this.lowestOmega = 2.0D*Math.PI*low; + this.lowestSet = true; + if(this.highestSet && this.numberSet)this.calculateFrequencies(); + } + + // Set lowest radial frequency + public void setLowRadialFrequency(double low){ + this.lowestOmega = low; + this.lowestFrequency = low/(2.0D*Math.PI); + this.lowestSet = true; + if(this.highestSet && this.numberSet)this.calculateFrequencies(); + } + + // Set highest frequency in Hz + public void setHighFrequency(double high){ + this.highestFrequency = high; + this.highestOmega = 2.0D*Math.PI*high; + this.highestSet = true; + if(this.lowestSet && this.numberSet)this.calculateFrequencies(); + } + + // Set highest radial frequency + public void setHighRadialFrequency(double high){ + this.highestOmega = high; + this.highestFrequency = high/(2.0D*Math.PI); + this.highestSet = true; + if(this.lowestSet && this.numberSet)this.calculateFrequencies(); + } + + + // Calculate frequencies + private void calculateFrequencies(){ + if(this.logOrLinear){ + double logLow = Fmath.log10(this.lowestFrequency); + double logHigh = Fmath.log10(this.highestFrequency); + this.increment = (logHigh - logLow)/(this.numberOfFrequencies - 1); + this.frequencies = new double[this.numberOfFrequencies]; + this.log10frequencies = new double[this.numberOfFrequencies]; + this.omegas = new double[this.numberOfFrequencies]; + this.log10omegas = new double[this.numberOfFrequencies]; + this.log10frequencies[0] = logLow; + this.log10frequencies[this.numberOfFrequencies-1] = logHigh; + for(int i=1; i<this.numberOfFrequencies-1; i++)this.log10frequencies[i] = this.log10frequencies[i-1] + this.increment; + for(int i=0; i<this.numberOfFrequencies; i++){ + this.frequencies[i] = Math.pow(10.0D, this.log10frequencies[i]); + this.omegas[i] = this.frequencies[i]*2.0D*Math.PI; + this.log10omegas[i] = Fmath.log10(this.omegas[i]); + } + } + else{ + this.increment = (this.highestFrequency - this.lowestFrequency)/(this.numberOfFrequencies - 1); + this.frequencies = new double[this.numberOfFrequencies]; + this.frequencies[0] = this.lowestFrequency; + this.log10frequencies = new double[this.numberOfFrequencies]; + this.omegas = new double[this.numberOfFrequencies]; + this.log10omegas = new double[this.numberOfFrequencies]; + this.frequencies[this.numberOfFrequencies-1] = this.highestFrequency; + for(int i=1; i<this.numberOfFrequencies-1; i++)this.frequencies[i] = this.frequencies[i-1] + this.increment; + for(int i=0; i<this.numberOfFrequencies; i++){ + this.log10frequencies[i] = Fmath.log10(this.frequencies[i]); + this.omegas[i] = this.frequencies[i]*2.0D*Math.PI; + this.log10omegas[i] = Fmath.log10(this.omegas[i]); + } + } + this.frequenciesSet = true; + } + + // Set linear option + public void setLinearPlot(){ + this.logOrLinear = false; + if(this.lowestSet && this.highestSet && this.numberSet)this.calculateFrequencies(); + + } + + // Set log10 option + public void setLog10Plot(){ + this.logOrLinear = true; + if(this.lowestSet && this.highestSet && this.numberSet)this.calculateFrequencies(); + } + + // Enter the applied voltage + public void setAppliedVoltage(double voltage){ + this.appliedVoltage = new Complex(voltage, 0.0D); + this.voltageSet = true; + } + + // Enter the reference impedance - resistive + public void setReferenceImpedance(double resistance){ + this.referenceImpedance = new Complex(resistance, 0.0D); + this.referenceSet = true; + } + + // Enter the reference impedance - reactive + public void setReferenceImpedance(double real, double imag){ + this.referenceImpedance = new Complex(real, imag); + this.referenceSet = true; + } + + // Enter the reference impedance - reactive + public void setReferenceImpedance(Complex impedance){ + this.referenceImpedance = impedance; + this.referenceSet = true; + } + + // set model number - parameters supplied as an array + public void setModel(int modelNumber, double[] parameters){ + if(modelNumber == 0 || modelNumber>Impedance.numberOfModels)throw new IllegalArgumentException("The model number, " + modelNumber + ", must lie between 1 and " + Impedance.numberOfModels + " inclusive"); + this.modelNumber = modelNumber; + this.parameters = parameters; + this.modelParameterSymbols = Impedance.modelComponents(modelNumber); + this.numberOfParameters = modelParameterSymbols.length; + if(this.numberOfParameters != this.parameters.length)throw new IllegalArgumentException("The number of model parametes passed, " + parameters.length + ", does not match the number required, " + this.numberOfParameters + ", by model number " + modelNumber); + this.parametersSet = true; + this.modelSet = true; + } + + // set model number - parameters supplied as an array - parameter symbols also supplied + public void setModel(int modelNumber, double[] parameters, String[] symbols){ + if(modelNumber == 0 || modelNumber>Impedance.numberOfModels)throw new IllegalArgumentException("The model number, " + modelNumber + ", must lie between 1 and " + Impedance.numberOfModels + " inclusive"); + this.modelNumber = modelNumber; + this.parameters = parameters; + this.modelParameterSymbols = Impedance.modelComponents(modelNumber); + this.numberOfParameters = modelParameterSymbols.length; + if(this.numberOfParameters != this.parameters.length)throw new IllegalArgumentException("The number of model parametes passed, " + parameters.length + ", does not match the numbber required, " + this.numberOfParameters + ", by model number " + modelNumber); + if(this.numberOfParameters != symbols.length)throw new IllegalArgumentException("The number of model symbols passed, " + symbols.length + ", does not match the number required, " + this.numberOfParameters + ", by model number " + modelNumber); + this.modelParameterSymbols = symbols; + this.parametersSet = true; + this.modelSet = true; + } + + // set model number - parameters read in through a dialog box + public void setModel(int modelNumber){ + if(modelNumber == 0 || modelNumber>Impedance.numberOfModels)throw new IllegalArgumentException("The model number, " + modelNumber + ", must lie between 1 and " + Impedance.numberOfModels + " inclusive"); + this.modelNumber = modelNumber; + this.modelSet = true; + this.modelParameterSymbols = Impedance.modelComponents(modelNumber); + this.numberOfParameters = modelParameterSymbols.length; + this.parameters = new double[this.numberOfParameters]; + + // Read in parameter values + int ii = 0; // counter + String symbol = null; + while(ii<this.numberOfParameters){ + symbol = modelParameterSymbols[ii]; + if(symbol.trim().charAt(0)=='R'){ + parameters[ii] = Db.readDouble("Enter resistance " + symbol.trim() + " [ohms]"); + ii++; + } + else{ + if(symbol.trim().charAt(0)=='C'){ + parameters[ii] = Db.readDouble("Enter capacitance " + symbol.trim() + " [farads]"); + ii++; + } + else{ + if(symbol.trim().charAt(0)=='L'){ + parameters[ii] = Db.readDouble("Enter inductance " + symbol.trim() + " [henries]"); + ii++; + } + else{ + if(symbol.trim().charAt(0)=='W'){ + parameters[ii] = Db.readDouble("Enter 'infinite' Warburg constant, sigma, " + symbol.trim() + " [ohms*sqrt(radians)]"); + ii++; + } + else{ + if(symbol.trim().charAt(0)=='F'){ + parameters[ii] = Db.readDouble("Enter 'finite' Warburg constant, sigma, " + symbol.trim() + " [SI units]"); + ii++; + + parameters[ii] = Db.readDouble("Enter 'finite' Warburg power, alpha, " + symbol.trim()); + ii++; + + } + else{ + if(symbol.trim().charAt(0)=='Q'){ + parameters[ii] = Db.readDouble("Enter CPE constant, sigma, " + symbol.trim() + " [SI units]"); + ii++; + + parameters[ii] = Db.readDouble("Enter CPE power, alpha, " + symbol.trim()); + ii++; + } + } + } + } + } + } + } + this.parametersSet = true; + } + + + // set user supplied model parameters - supplied as an array - symbols automatically listed as P1, P2 etc + public void setModel(ImpedSpecModel userModel, double[] parameters){ + this.userModel = userModel; + this.parameters = parameters; + this.numberOfParameters = parameters.length; + this.modelParameterSymbols = new String[this.numberOfParameters]; + for(int i=0; i<numberOfParameters; i++)this.modelParameterSymbols[i] = "P" + (i+1); + this.parametersSet = true; + } + + // set user supplied model parameters - supplied as an array - parameter symbols also supplied + public void setModel(ImpedSpecModel userModel, double[] parameters, String[] symbols){ + this.userModel = userModel; + this.parameters = parameters; + this.modelParameterSymbols = symbols; + this.numberOfParameters = parameters.length; + this.parametersSet = true; + } + + // Calculate impedances + public Complex[] calculateImpedances(){ + if(!parametersSet)throw new IllegalArgumentException("model parameters values have not been entered"); + if(!frequenciesSet)throw new IllegalArgumentException("frequency values have not been entered"); + this.impedances = Complex.oneDarray(this.numberOfFrequencies); + if(this.modelSet){ + for(int i=0; i<this.numberOfFrequencies; i++){ + this.impedances[i] = Impedance.modelImpedance(this.parameters, this.omegas[i], this.modelNumber); + } + } + else{ + for(int i=0; i<this.numberOfFrequencies; i++){ + this.impedances[i] = this.userModel.modelImpedance(this.parameters, this.omegas[i]); + } + } + this.magnitudesZ = new double[this.numberOfFrequencies]; + this.phasesRadZ = new double[this.numberOfFrequencies]; + this.phasesDegZ = new double[this.numberOfFrequencies]; + this.realZ = new double[this.numberOfFrequencies]; + this.imagZ = new double[this.numberOfFrequencies]; + this.magnitudesV = new double[this.numberOfFrequencies]; + this.phasesRadV = new double[this.numberOfFrequencies]; + this.phasesDegV = new double[this.numberOfFrequencies]; + this.realV = new double[this.numberOfFrequencies]; + this.imagV = new double[this.numberOfFrequencies]; + this.voltages = Complex.oneDarray(this.numberOfFrequencies); + for(int i=0; i<this.numberOfFrequencies; i++){ + this.magnitudesZ[i] = Complex.abs(this.impedances[i]); + this.phasesRadZ[i] = Complex.arg(this.impedances[i]); + this.phasesDegZ[i] = Math.toDegrees(this.phasesRadZ[i]); + this.realZ[i] = this.impedances[i].getReal(); + this.imagZ[i] = this.impedances[i].getImag(); + if(this.voltageSet && this.referenceSet){ + this.voltages[i] = this.appliedVoltage.times(this.impedances[i].over(this.impedances[i].plus(this.referenceImpedance))); + this.magnitudesV[i] = Complex.abs(this.voltages[i]); + this.phasesRadV[i] = Complex.arg(this.voltages[i]); + this.phasesDegV[i] = Math.toDegrees(this.phasesRadV[i]); + this.realV[i] = this.voltages[i].getReal(); + this.imagV[i] = this.voltages[i].getImag(); + } + } + this.impedancesSet = true; + return this.impedances; + } + + // Get the simulation results as ArrayList + // complex impedances, real parts of the complex impedances, the imaginary parts of the complex impedances + // magnitudes, // phases (degrees), phases (radians), + // frequencies [Hz], log10(frequencies/Hz), radial frequencies (radians]), + public ArrayList<Object> getSimulationResultsAsArrayList(int nPoints){ + + if(!this.impedancesSet)calculateImpedances(); + + // determine points to be printed + if(nPoints>this.numberOfFrequencies)nPoints = this.numberOfFrequencies; + int increment = (int)Math.round((double)this.numberOfFrequencies/(double)nPoints); + int[] points = new int[nPoints]; + points[0] = 0; + for(int i=1; i<nPoints; i++)points[i] = points[i-1] + increment; + if(points[nPoints-1] != (this.numberOfFrequencies-1))points[nPoints-1] = this.numberOfFrequencies-1; + + // Load ArrayList with selected data + ArrayList<Object> selectedData = new ArrayList<Object>(); + + Complex[] imp = Complex.oneDarray(nPoints); + for(int i=0; i<nPoints; i++)imp[i] = impedances[points[i]]; + selectedData.add(Complex.copy(imp)); + + double[] hold = new double[nPoints]; + for(int i=0; i<nPoints; i++)hold[i] = realZ[points[i]]; + selectedData.add((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = imagZ[points[i]]; + selectedData.add((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = magnitudesZ[points[i]]; + selectedData.add((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = phasesDegZ[points[i]]; + selectedData.add((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = phasesRadZ[points[i]]; + selectedData.add((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = frequencies[points[i]]; + selectedData.add((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = log10frequencies[points[i]]; + selectedData.add((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = omegas[points[i]]; + selectedData.add((double[])hold.clone()); + + if(this.voltageSet && this.referenceSet){ + selectedData.add(new Double(this.appliedVoltage.getReal())); + + selectedData.add(this.referenceImpedance); + + for(int i=0; i<nPoints; i++)imp[i] = voltages[points[i]]; + selectedData.add(Complex.copy(imp)); + + for(int i=0; i<nPoints; i++)hold[i] = realV[points[i]]; + selectedData.add((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = imagV[points[i]]; + selectedData.add((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = magnitudesV[points[i]]; + selectedData.add((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = phasesDegV[points[i]]; + selectedData.add((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = phasesRadV[points[i]]; + selectedData.add((double[])hold.clone()); + } + else{ + for(int i=0; i<8; i++)selectedData.add(null); + } + + return selectedData; + } + + + + // Get the simulation results as Vector + // complex impedances, real parts of the complex impedances, the imaginary parts of the complex impedances + // magnitudes, // phases (degrees), phases (radians), + // frequencies [Hz], log10(frequencies/Hz), radial frequencies (radians]), + public Vector<Object> getSimulationResultsAsVector(int nPoints){ + + if(!this.impedancesSet)calculateImpedances(); + + // determine points to be printed + if(nPoints>this.numberOfFrequencies)nPoints = this.numberOfFrequencies; + int increment = (int)Math.round((double)this.numberOfFrequencies/(double)nPoints); + int[] points = new int[nPoints]; + points[0] = 0; + for(int i=1; i<nPoints; i++)points[i] = points[i-1] + increment; + if(points[nPoints-1] != (this.numberOfFrequencies-1))points[nPoints-1] = this.numberOfFrequencies-1; + + // Load Vector with selected data + Vector<Object> vec = new Vector<Object>(); + + Complex[] imp = Complex.oneDarray(nPoints); + for(int i=0; i<nPoints; i++)imp[i] = impedances[points[i]]; + vec.addElement(Complex.copy(imp)); + + double[] hold = new double[nPoints]; + for(int i=0; i<nPoints; i++)hold[i] = realZ[points[i]]; + vec.addElement((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = imagZ[points[i]]; + vec.addElement((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = magnitudesZ[points[i]]; + vec.addElement((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = phasesDegZ[points[i]]; + vec.addElement((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = phasesRadZ[points[i]]; + vec.addElement((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = frequencies[points[i]]; + vec.addElement((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = log10frequencies[points[i]]; + vec.addElement((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = omegas[points[i]]; + vec.addElement((double[])hold.clone()); + + if(this.voltageSet && this.referenceSet){ + vec.addElement(new Double(this.appliedVoltage.getReal())); + + vec.addElement(this.referenceImpedance); + + for(int i=0; i<nPoints; i++)imp[i] = voltages[points[i]]; + vec.addElement(Complex.copy(imp)); + + for(int i=0; i<nPoints; i++)hold[i] = realV[points[i]]; + vec.addElement((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = imagV[points[i]]; + vec.addElement((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = magnitudesV[points[i]]; + vec.addElement((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = phasesDegV[points[i]]; + vec.addElement((double[])hold.clone()); + + for(int i=0; i<nPoints; i++)hold[i] = phasesRadV[points[i]]; + vec.addElement((double[])hold.clone()); + } + else{ + for(int i=0; i<8; i++)vec.addElement(null); + } + + return vec; + } + + // Get the simulation results as Vector + // complex impedances, real parts of the complex impedances, the imaginary parts of the complex impedances + // magnitudes, // phases (degrees), phases (radians), + // frequencies [Hz], log10(frequencies/Hz), radial frequencies (radians]), + public Vector<Object> getSimulationResults(int nPoints){ + return this.getSimulationResultsAsVector(nPoints); + } + + // Plot impedance magnitude versus frequency + public void plotImpedanceMagnitudes(){ + this.plotImpedanceMagnitudeVersusFrequency(); + } + + // Plot impedance magnitude versus frequency + public void plotImpedanceMagnitudeVersusFrequency(){ + String[] dAndT= this.dateAndTime(); + String graphTitle1 = "ImpedSpecSimulation program: Impedance Magnitude versus Frequency [" + dAndT[0] + " " + dAndT[1] + "]"; + String graphTitle2 = this.simulationTitle; + if(logOrLinear){ + this.impedanceMagnitudeVersusLogFrequencyPlot(graphTitle1, graphTitle2); + } + else{ + this.impedanceMagnitudeVersusFrequencyPlot(graphTitle1, graphTitle2); + } + } + + // Plot impedance magnitude versus frequency (old signature) + public void plotMagnitudeVersusFrequency(){ + this.plotImpedanceMagnitudeVersusFrequency(); + } + + // Plot magnitude versus log10 frequency + private void impedanceMagnitudeVersusLogFrequencyPlot(String graphTitle1, String graphTitle2){ + + if(!this.impedancesSet)calculateImpedances(); + + double[][] data = new double[2][this.numberOfFrequencies]; + data[0] = this.log10frequencies; + data[1] = this.magnitudesZ; + PlotGraph pg = new PlotGraph(data); + pg.setLine(3); + pg.setPoint(0); + pg.setGraphTitle(graphTitle1); + pg.setGraphTitle2(graphTitle2); + pg.setXaxisLegend("Log10[Frequency / Hz]"); + pg.setYaxisLegend("Impedance Magnitude"); + pg.plot(); + } + + // Plot magnitude versus frequency + private void impedanceMagnitudeVersusFrequencyPlot(String graphTitle1, String graphTitle2){ + + if(!this.impedancesSet)calculateImpedances(); + + double[][] data = new double[2][this.numberOfFrequencies]; + data[0] = this.frequencies; + data[1] = this.magnitudesZ; + PlotGraph pg = new PlotGraph(data); + pg.setLine(3); + pg.setPoint(0); + pg.setGraphTitle(graphTitle1); + pg.setGraphTitle2(graphTitle2); + pg.setXaxisLegend("Frequency"); + pg.setXaxisUnitsName("Hz"); + pg.setYaxisLegend("Impedance Magnitude"); + pg.plot(); + } + + // Plot impedance phase versus frequency + public void plotImpedancePhases(){ + this.plotImpedancePhaseVersusFrequency(); + } + + // Plot impedance phase versus frequency + public void plotImpedancePhaseVersusFrequency(){ + String[] dAndT= this.dateAndTime(); + String graphTitle1 = "ImpedSpecSimulation program: Impedance Phase versus Frequency [" + dAndT[0] + " " + dAndT[1] + "]"; + String graphTitle2 = this.simulationTitle; + if(logOrLinear){ + this.impedancePhaseVersusLogFrequencyPlot(graphTitle1, graphTitle2); + } + else{ + this.impedancePhaseVersusFrequencyPlot(graphTitle1, graphTitle2); + } + } + + // Plot impedance phase versus frequency (old signature) + public void plotPhaseVersusFrequency(){ + this.plotImpedancePhaseVersusFrequency(); + } + + // Plot phase versus log10 frequency + private void impedancePhaseVersusLogFrequencyPlot(String graphTitle1, String graphTitle2){ + + if(!this.impedancesSet)calculateImpedances(); + + double[][] data = new double[2][this.numberOfFrequencies]; + data[0] = this.log10frequencies; + data[1] = this.phasesDegZ; + PlotGraph pg = new PlotGraph(data); + pg.setLine(3); + pg.setPoint(0); + pg.setGraphTitle(graphTitle1); + pg.setGraphTitle2(graphTitle2); + pg.setXaxisLegend("Log10[Frequency / Hz]"); + pg.setYaxisLegend("Impedance Phase"); + pg.setYaxisUnitsName("degrees"); + pg.plot(); + } + + // Plot phase versus frequency + private void impedancePhaseVersusFrequencyPlot(String graphTitle1, String graphTitle2){ + + if(!this.impedancesSet)calculateImpedances(); + + double[][] data = new double[2][this.numberOfFrequencies]; + data[0] = this.frequencies; + data[1] = this.phasesDegZ; + PlotGraph pg = new PlotGraph(data); + pg.setLine(3); + pg.setPoint(0); + pg.setGraphTitle(graphTitle1); + pg.setGraphTitle2(graphTitle2); + pg.setXaxisLegend("Frequency"); + pg.setXaxisUnitsName("Hz"); + pg.setYaxisLegend("Impedance Phase"); + pg.setYaxisUnitsName("degrees"); + pg.plot(); + } + + // Cole-Cole Plot + public void plotColeCole(){ + String[] dAndT= this.dateAndTime(); + String graphTitle1 = "ImpedSpecSimulation program: Cole - Cole plot [" + dAndT[0] + " " + dAndT[1] + "]"; + String graphTitle2 = this.simulationTitle; + this.coleColePlot(graphTitle1, graphTitle2); + } + + + // Cole-Cole Plot + private void coleColePlot(String graphTitle1, String graphTitle2){ + + if(!this.impedancesSet)calculateImpedances(); + + double[][] data = new double[2][this.numberOfFrequencies]; + for(int i=0; i<this.numberOfFrequencies; i++){ + data[0][i] = this.realZ[this.numberOfFrequencies - i - 1]; + data[1][i] = -this.imagZ[this.numberOfFrequencies - i - 1]; + } + PlotGraph pg = new PlotGraph(data); + pg.setLine(3); + pg.setPoint(0); + pg.setGraphTitle(graphTitle1); + pg.setGraphTitle2(graphTitle2); + pg.setXaxisLegend("Real[Impedance / ohms]"); + pg.setYaxisLegend("-Imag[Impedance / ohms]"); + pg.plot(); + } + + + // Plot voltage magnitude versus frequency + public void plotVoltageMagnitudes(){ + this.plotVoltageMagnitudeVersusFrequency(); + } + + // Plot voltage magnitude versus frequency + public void plotVoltageMagnitudeVersusFrequency(){ + + if(this.voltageSet && this.referenceSet){ + String[] dAndT= this.dateAndTime(); + String graphTitle1 = "ImpedSpecSimulation program: Voltage Magnitude versus Frequency [" + dAndT[0] + " " + dAndT[1] + "]"; + String graphTitle2 = this.simulationTitle; + if(logOrLinear){ + this.voltageMagnitudeVersusLogFrequencyPlot(graphTitle1, graphTitle2); + } + else{ + this.voltageMagnitudeVersusFrequencyPlot(graphTitle1, graphTitle2); + } + } + else{ + System.out.println("A Voltage phase plot cannot be displayed, either no applied"); + System.out.println("voltage and/or reference impedance has been entered"); + } + + } + + + // Plot voltage magnitude versus log10 frequency + private void voltageMagnitudeVersusLogFrequencyPlot(String graphTitle1, String graphTitle2){ + + if(!this.impedancesSet)calculateImpedances(); + + double[][] data = new double[2][this.numberOfFrequencies]; + data[0] = this.log10frequencies; + data[1] = this.magnitudesV; + PlotGraph pg = new PlotGraph(data); + pg.setLine(3); + pg.setPoint(0); + pg.setGraphTitle(graphTitle1); + pg.setGraphTitle2(graphTitle2); + pg.setXaxisLegend("Log10[Frequency / Hz]"); + pg.setYaxisLegend("Voltage Magnitude"); + pg.plot(); + } + + // Plot voltage magnitude versus frequency + private void voltageMagnitudeVersusFrequencyPlot(String graphTitle1, String graphTitle2){ + + if(!this.impedancesSet)calculateImpedances(); + + double[][] data = new double[2][this.numberOfFrequencies]; + data[0] = this.frequencies; + data[1] = this.magnitudesV; + PlotGraph pg = new PlotGraph(data); + pg.setLine(3); + pg.setPoint(0); + pg.setGraphTitle(graphTitle1); + pg.setGraphTitle2(graphTitle2); + pg.setXaxisLegend("Frequency"); + pg.setXaxisUnitsName("Hz"); + pg.setYaxisLegend("Voltage Magnitude"); + pg.plot(); + } + + + // Plot voltage phase versus frequency + public void plotVoltagePhases(){ + this.plotVoltagePhaseVersusFrequency(); + } + + // Plot voltage phase versus frequency + public void plotVoltagePhaseVersusFrequency(){ + + if(this.voltageSet && this.referenceSet){ + String[] dAndT= this.dateAndTime(); + String graphTitle1 = "ImpedSpecSimulation program: Voltage Phase versus Frequency [" + dAndT[0] + " " + dAndT[1] + "]"; + String graphTitle2 = this.simulationTitle; + if(logOrLinear){ + this.voltagePhaseVersusLogFrequencyPlot(graphTitle1, graphTitle2); + } + else{ + this.voltagePhaseVersusFrequencyPlot(graphTitle1, graphTitle2); + } + } + else{ + System.out.println("A Voltage phase plot cannot be displayed, either no applied"); + System.out.println("voltage and/or reference impedance has been entered"); + } + } + + + // Plot voltage phase versus log10 frequency + private void voltagePhaseVersusLogFrequencyPlot(String graphTitle1, String graphTitle2){ + + if(!this.impedancesSet)calculateImpedances(); + + double[][] data = new double[2][this.numberOfFrequencies]; + data[0] = this.log10frequencies; + data[1] = this.phasesDegV; + PlotGraph pg = new PlotGraph(data); + pg.setLine(3); + pg.setPoint(0); + pg.setGraphTitle(graphTitle1); + pg.setGraphTitle2(graphTitle2); + pg.setXaxisLegend("Log10[Frequency / Hz]"); + pg.setYaxisLegend("Voltage Phase"); + pg.setYaxisUnitsName("degrees"); + pg.plot(); + } + + // Plot phase versus frequency + private void voltagePhaseVersusFrequencyPlot(String graphTitle1, String graphTitle2){ + + if(!this.impedancesSet)calculateImpedances(); + + double[][] data = new double[2][this.numberOfFrequencies]; + data[0] = this.frequencies; + data[1] = this.phasesDegV; + PlotGraph pg = new PlotGraph(data); + pg.setLine(3); + pg.setPoint(0); + pg.setGraphTitle(graphTitle1); + pg.setGraphTitle2(graphTitle2); + pg.setXaxisLegend("Frequency"); + pg.setXaxisUnitsName("Hz"); + pg.setYaxisLegend("Voltage Phase"); + pg.setYaxisUnitsName("degrees"); + pg.plot(); + } + + // Returns date and time + public String[] dateAndTime(){ + Date d = new Date(); + String[] ret = new String[2]; + ret[0] = DateFormat.getDateInstance().format(d); + ret[1] = DateFormat.getTimeInstance().format(d); + return ret; + } + + // Print simulation to text file - nPoints is the number of points to be printed + public void printToTextFile(int nPoints){ + String fileName = "ImpedSpecSimulationOutput.txt"; + this.fileType = true; + this.printToTextFile(fileName, nPoints); + } + + // Print simulation to text file - nPoints is the number of points to be printed + public void print(int nPoints){ + String fileName = "ImpedSpecSimulationOutput.txt"; + this.fileType = true; + this.printToTextFile(fileName, nPoints); + } + + // Print simulation to text file - nPoints is the number of points to be printed + public void print(String fileName, int nPoints){ + this.printToTextFile(fileName, nPoints); + } + + // Print simulation to text file - nPoints is the number of points to be printed + public void printToTextFile(String fileName, int nPoints){ + + if(!this.impedancesSet)calculateImpedances(); + + int field = 10; // output field length + int trunc = 4; // truncation length + + // Check extension + fileName = fileName.trim(); + int dotPosition = fileName.indexOf('.'); + if(dotPosition==-1)fileName += ".txt"; + + // determine points to be printed + if(nPoints>this.numberOfFrequencies)nPoints = this.numberOfFrequencies; + int increment = (int)Math.round((double)this.numberOfFrequencies/(double)nPoints); + int[] points = new int[nPoints]; + points[0] = 0; + for(int i=1; i<nPoints; i++)points[i] = points[i-1] + increment; + if(points[nPoints-1] != (this.numberOfFrequencies-1))points[nPoints-1] = this.numberOfFrequencies-1; + + // instantiate a FileOutput + FileOutput fout = null; + if(this.fileType){ + fout = new FileOutput(fileName, 'n'); + } + else{ + fout = new FileOutput(fileName); + } + + // print header + fout.println("ImpedSpecSimulation Program Output File: " + this.simulationTitle); + fout.dateAndTimeln(fileName); + fout.println(); + if(this.modelSet){ + fout.println("Circuit - model number " + this.modelNumber); + } + else{ + fout.println("Circuit supplied by the user"); + } + fout.println(); + + // print circuit parameters + fout.println("Circuit Parameters"); + fout.printtab("Parameters"); + fout.println("Value (SI unit)"); + for(int i=0; i<this.numberOfParameters; i++){ + fout.printtab(this.modelParameterSymbols[i], field); + fout.println(this.parameters[i]); + } + fout.println(); + + // Print impedance data for each frequency + field=14; + fout.println("Frequecy - Impedance data"); + + fout.print("Frequency", field); + fout.print("Magnitude", field); + fout.print("Phase", field); + fout.print("Phase", field); + fout.print("Real[Z]", field); + fout.print("Imag[Z]", field); + fout.print("Log10(freq)", field); + fout.println("Radial frequency"); + + fout.print("/Hz [freq]", field); + fout.print(" ", field); + fout.print("/degrees", field); + fout.print("/radians", field); + fout.print("/ohms", field); + fout.print("/ohms", field); + fout.print(" ", field); + fout.println("/radians"); + + for(int i=0; i<nPoints; i++){ + fout.print(Fmath.truncate(this.frequencies[points[i]], trunc), field); + fout.print(Fmath.truncate(this.magnitudesZ[points[i]], trunc), field); + fout.print(Fmath.truncate(this.phasesDegZ[points[i]], trunc), field); + fout.print(Fmath.truncate(this.phasesRadZ[points[i]], trunc), field); + fout.print(Fmath.truncate(this.realZ[points[i]], trunc), field); + fout.print(Fmath.truncate(this.imagZ[points[i]], trunc), field); + fout.print(Fmath.truncate(this.log10frequencies[points[i]], trunc), field); + fout.println(Fmath.truncate(this.omegas[points[i]], trunc)); + } + fout.println(); + + if(this.voltageSet && this.referenceSet){ + fout.println("Aplied voltage: " + this.appliedVoltage.getReal() + " volts"); + fout.println(); + + fout.println("Reference impedance: " + this.referenceImpedance + " ohms"); + fout.println(); + + // Print voltage data for each frequency + field=14; + fout.println("Frequecy - Voltage data"); + + fout.print("Frequency", field); + fout.print("Magnitude", field); + fout.print("Phase", field); + fout.print("Phase", field); + fout.print("Real[V]", field); + fout.print("Imag[V]", field); + fout.print("Log10(freq)", field); + fout.println("Radial frequency"); + + fout.print("/Hz [freq]", field); + fout.print(" ", field); + fout.print("/degrees", field); + fout.print("/radians", field); + fout.print("/volts", field); + fout.print("/volts", field); + fout.print(" ", field); + fout.println("/radians"); + + for(int i=0; i<nPoints; i++){ + fout.print(Fmath.truncate(this.frequencies[points[i]], trunc), field); + fout.print(Fmath.truncate(this.magnitudesV[points[i]], trunc), field); + fout.print(Fmath.truncate(this.phasesDegV[points[i]], trunc), field); + fout.print(Fmath.truncate(this.phasesRadV[points[i]], trunc), field); + fout.print(Fmath.truncate(this.realV[points[i]], trunc), field); + fout.print(Fmath.truncate(this.imagV[points[i]], trunc), field); + fout.print(Fmath.truncate(this.log10frequencies[points[i]], trunc), field); + fout.println(Fmath.truncate(this.omegas[points[i]], trunc)); + } + } + + // close file + fout.close(); + } + + // Print simulation to text file that can be sensibly read by MS Excel - nPoints is the number of points to be printed + public void printToExcelFile(int nPoints){ + String fileName = "ImpedSpecSimulationOutput.xls"; + this.fileType = true; + this.printToExcelFile(fileName, nPoints); + } + + // Print simulation to text file that can be sensibly read by MS Excel - nPoints is the number of points to be printed + public void printForExcel(int nPoints){ + String fileName = "ImpedSpecSimulationOutput.xls"; + this.fileType = true; + this.printToExcelFile(fileName, nPoints); + } + + // Print simulation to text file that can be sensibly read by MS Excel - nPoints is the number of points to be printed + public void printForExcel(String fileName, int nPoints){ + this.printToExcelFile(fileName, nPoints); + } + + // Print simulation to text file that can be sensibly read by MS Excel - nPoints is the number of points to be printed + public void printToExcelFile(String fileName, int nPoints){ + + if(!this.impedancesSet)calculateImpedances(); + + int field = 10; // output field length + int trunc = 4; // truncation length + + // Check extension + fileName = fileName.trim(); + int dotPosition = fileName.indexOf('.'); + if(dotPosition==-1){ + fileName += ".xls"; + } + else{ + fileName = fileName.substring(0, dotPosition) + ".xls"; + } + + // determine points to be printed + if(nPoints>this.numberOfFrequencies)nPoints = this.numberOfFrequencies; + int increment = (int)Math.round((double)this.numberOfFrequencies/(double)nPoints); + int[] points = new int[nPoints]; + points[0] = 0; + for(int i=1; i<nPoints; i++)points[i] = points[i-1] + increment; + if(points[nPoints-1] != (this.numberOfFrequencies-1))points[nPoints-1] = this.numberOfFrequencies-1; + + // instantiate a FileOutput + FileOutput fout = null; + if(this.fileType){ + fout = new FileOutput(fileName, 'n'); + } + else{ + fout = new FileOutput(fileName); + } + + // print header + fout.println("ImpedSpecSimulation Program Output File: " + this.simulationTitle); + fout.dateAndTimeln(fileName); + fout.println(); + if(this.modelSet){ + fout.println("Circuit - model number " + this.modelNumber); + } + else{ + fout.println("Circuit supplied by the user"); + } + fout.println(); + + // print circuit parameters + fout.println("Circuit Parameters"); + fout.printtab("Parameters"); + fout.println("Value (SI unit)"); + for(int i=0; i<this.numberOfParameters; i++){ + fout.printtab(this.modelParameterSymbols[i], field); + fout.println(this.parameters[i]); + } + fout.println(); + + // Print impedance data for each frequency + field=10; + fout.println("Frequecy - Impedance data"); + + fout.printtab("Frequency", field); + fout.printtab("Magnitude", field); + fout.printtab("Phase", field); + fout.printtab("Phase", field); + fout.printtab("Real[Z]", field); + fout.printtab("Imag[Z]", field); + fout.printtab("Log10(freq)", field); + fout.println("Radial frequency"); + + fout.printtab("/Hz [freq]", field); + fout.printtab(" ", field); + fout.printtab("/degrees", field); + fout.printtab("/radians", field); + fout.printtab("/ohms", field); + fout.printtab("/ohms", field); + fout.printtab(" ", field); + fout.println("/radians"); + + for(int i=0; i<nPoints; i++){ + fout.printtab(Fmath.truncate(this.frequencies[points[i]], trunc), field); + fout.printtab(Fmath.truncate(this.magnitudesZ[points[i]], trunc), field); + fout.printtab(Fmath.truncate(this.phasesDegZ[points[i]], trunc), field); + fout.printtab(Fmath.truncate(this.phasesRadZ[points[i]], trunc), field); + fout.printtab(Fmath.truncate(this.realZ[points[i]], trunc), field); + fout.printtab(Fmath.truncate(this.imagZ[points[i]], trunc), field); + fout.printtab(Fmath.truncate(this.log10frequencies[points[i]], trunc), field); + fout.println(Fmath.truncate(this.omegas[points[i]], trunc)); + } + fout.println(); + + if(this.voltageSet && this.referenceSet){ + fout.println("Aplied voltage: " + this.appliedVoltage.getReal() + " volts"); + fout.println(); + + fout.println("Reference impedance: " + this.referenceImpedance + " ohms"); + fout.println(); + + // Print voltage data for each frequency + field=14; + fout.println("Frequecy - Voltage data"); + + fout.printtab("Frequency", field); + fout.printtab("Magnitude", field); + fout.printtab("Phase", field); + fout.printtab("Phase", field); + fout.printtab("Real[V]", field); + fout.printtab("Imag[V]", field); + fout.printtab("Log10(freq)", field); + fout.println("Radial frequency"); + + fout.printtab("/Hz [freq]", field); + fout.printtab(" ", field); + fout.printtab("/degrees", field); + fout.printtab("/radians", field); + fout.printtab("/volts", field); + fout.printtab("/volts", field); + fout.printtab(" ", field); + fout.println("/radians"); + + for(int i=0; i<nPoints; i++){ + fout.printtab(Fmath.truncate(this.frequencies[points[i]], trunc), field); + fout.printtab(Fmath.truncate(this.magnitudesV[points[i]], trunc), field); + fout.printtab(Fmath.truncate(this.phasesDegV[points[i]], trunc), field); + fout.printtab(Fmath.truncate(this.phasesRadV[points[i]], trunc), field); + fout.printtab(Fmath.truncate(this.realV[points[i]], trunc), field); + fout.printtab(Fmath.truncate(this.imagV[points[i]], trunc), field); + fout.printtab(Fmath.truncate(this.log10frequencies[points[i]], trunc), field); + fout.println(Fmath.truncate(this.omegas[points[i]], trunc)); + } + } + + // close file + fout.close(); + } +} + + + + diff --git a/src/main/java/flanagan/circuits/Impedance.java b/src/main/java/flanagan/circuits/Impedance.java new file mode 100755 index 0000000000000000000000000000000000000000..f6dd961b4bfdc41429b7c5c90aa2ea695ba974d7 --- /dev/null +++ b/src/main/java/flanagan/circuits/Impedance.java @@ -0,0 +1,850 @@ +/* Class Impedance +* +* Basic impedance methods +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: May 2007 +* UPDATE: 11, 12, 15, 22, 26 June and 15 July 2007 +* +* DOCUMENTATION: +* See Michael T Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Impedance.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ImpedSpecSimulation.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ImpedSpecRegression.html + +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) May 2007, July 2007 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.circuits; + +import flanagan.complex.Complex; +import flanagan.math.Fmath; + +public class Impedance{ + + // class variables + protected static int numberOfModels = 44; // number of circuit models included in this class + + // Constructor + public Impedance(){ + } + + // Get the resistance complex impedance + public static Complex resistanceImpedance(double resistance){ + return new Complex(resistance, 0.0D); + } + + // Get the capacitance complex impedance for a given radial frequency + public static Complex capacitanceImpedance(double capacitance, double omega){ + return new Complex(0.0D, -1.0D/(capacitance*omega)); + } + + // Get the inductance complex impedance for a given radial frequency + public static Complex inductanceImpedance(double inductance, double omega){ + return new Complex(0.0D, inductance*omega); + } + + // Get the 'infinite' Warburg impedance + public static Complex infiniteWarburgImpedance(double sigma, double omega){ + double term = sigma/Math.sqrt(omega); + return new Complex(term, -term); + } + + // Get the 'finite' Warburg impedance + public static Complex finiteWarburgImpedance(double sigma, double tanhConst, double omega){ + Complex zVal1 = new Complex(sigma*Math.sqrt(omega), 0.0D); + Complex zVal2 = new Complex(tanhConst, 0.0D); + Complex zVal3 = new Complex(0.0D, omega); + Complex zVal4 = Complex.sqrt(zVal3); + Complex zVal5 = zVal2.times(zVal4); + Complex zVal6 = Complex.tanh(zVal5); + Complex zVal7 = zVal1.times(zVal6); + Complex zVal8 = Complex.plusOne().minus(Complex.plusJay()); + return zVal8.times(zVal7); + } + + // Get the constant phase element impedance + public static Complex constantPhaseElementImpedance(double cpeCoeff, double alpha, double omega){ + Complex jOmega = new Complex(0.0D, omega); + Complex jOmegaAlpha = Complex.pow(jOmega,-alpha); + Complex coeff = new Complex(cpeCoeff, 0.0D); + return coeff.times(jOmegaAlpha); + } + + // Calculate the impedance of two impedances in series + public static Complex impedanceInSeries(Complex z1, Complex z2){ + return z1.plus(z2); + } + + // Calculate the impedance of two impedances in series + public static Complex impedanceInSeries(double z1, Complex z2){ + return z2.plus(z1); + } + + // Calculate the impedance of two impedances in series + public static Complex impedanceInSeries(Complex z1, double z2){ + return z1.plus(z2); + } + + // Calculate the impedance of two impedances in series + public static Complex impedanceInSeries(double z1, double z2){ + return new Complex(z1+z2, 0.0D); + } + + // Calculate the impedance of a resistor and capacitor in series + public static Complex rInSeriesWithC(double res, double cap, double omega){ + Complex ret = new Complex(res, -1.0D/(cap*omega)); + return ret; + } + + // Calculate the impedance of a resistor and an inductor in series + public static Complex rInSeriesWithL(double res, double ind, double omega){ + Complex ret = new Complex(res, ind*omega); + return ret; + } + + // Calculate the impedance of a capacitor and an inductor in series + public static Complex cInSeriesWithL(double cap, double ind, double omega){ + Complex z1 = new Complex(0.0D, -1.0D/(cap*omega)); + Complex z2 = new Complex(0.0D, ind*omega); + return z1.plus(z2); + } + + // Calculate the impedance of two impedances in parallel + public static Complex impedanceInParallel(Complex z1, Complex z2){ + Complex ret = z1.times(z2); + return ret.over(z1.plus(z2)); + } + + // Calculate the impedance of two impedances in parallel + public static Complex impedanceInParallel(Complex z1, double z2){ + Complex ret = z1.times(z2); + return ret.over(z1.plus(z2)); + } + + // Calculate the impedance of two impedances in parallel + public static Complex impedanceInParallel(double z1, Complex z2){ + Complex ret = z2.times(z1); + return ret.over(z2.plus(z1)); + } + + // Calculate the impedance of two impedances in parallel + public static Complex impedanceInParallel(double z1, double z2){ + return new Complex(z1*z2/(z1+z2), 0.0D); + } + + // Calculate the impedance of a resistor and capacitor in parallel + public static Complex rInParallelWithC(double res, double cap, double omega){ + Complex zC = new Complex(0.0D, -1.0D/(cap*omega)); + Complex zR = new Complex(res, 0.0D); + Complex ret = zC.times(zR); + return ret.over(zC.plus(zR)); + } + + // Calculate the impedance of a resistor and an inductor in parallel + public static Complex rInParallelWithL(double res, double ind, double omega){ + Complex zL = new Complex(0.0D, ind*omega); + Complex zR = new Complex(res, 0.0D); + Complex ret = zL.times(zR); + return ret.over(zL.plus(zR)); + } + + // Calculate the impedance of a capacitor and an inductor in parallel + public static Complex cInParallelWithL(double cap, double ind, double omega){ + Complex z1 = new Complex(0.0D, -1.0D/(cap*omega)); + Complex z2 = new Complex(0.0D, ind*omega); + Complex z3 = z1.plus(z2); + Complex z4 = z1.times(z2); + return z4.over(z3); + } + + // return model circuit component list + public static String[] modelComponents(int modelNumber){ + // Components within models + String[][] compName = {{" "},{"R1"},{"C1"},{"L1"},{"W1"},{"Fsigma1", "Fdelta1"},{"Qsigma1", "Qalpha1"},{"R1", "C1"},{"R1", "L1"},{"L1", "C1"},{"R1", "C1"},{"R1", "L1"},{"L1", "C1"},{"R1", "C1", "R2"},{"R1", "C1", "R2", "L1"},{"R1", "C1", "R2", "L1"},{"R1", "C1", "C2"},{"R1", "C1", "C2"},{"R1", "C1", "R2", "C2"},{"R1", "C1", "R2", "C2"},{"R1", "C1", "R2", "C2", "R3"},{"R1", "C1", "R2", "C2", "R3"},{"R1", "C1", "R2", "C2", "R3", "C3"},{"R1", "C1", "R2", "C2", "R3", "C3", "R4"},{"R1", "C1", "W1", "R2"},{"R1", "C1", "Fsigma1", "Fdelta1", "R2"},{"R1", "C1", "Qsigma1", "Qalpha1", "R2"},{"R1", "C1", "R2", "C2", "W1"},{"R1", "C1", "R2", "C2", "W3", "C3", "R4"}, {"R1", "C1", "R2", "Qsigma1", "Qalpha1"},{"R1", "C1", "R2", "Qsigma1", "Qalpha1", "R3"},{"R1", "Qsigma1", "Qalpha1", "R2", "Qsigma2", "Qalpha2", "R3", "Qsigma3", "Qalpha3"},{"R1", "Qsigma1", "Qalpha1", "R2", "Qsigma2", "Qalpha2", "R3", "Qsigma3", "Qalpha3", "R4"},{"R1", "Qsigma1", "Qalpha1", "R2", "Qsigma2", "Qalpha2", "R3", "Qsigma3", "Qalpha3", "R4", "C1"},{"C1", "Qsigma1", "Qalpha1", "C2", "Qsigma2", "Qalpha2", "C3", "Qsigma3", "Qalpha3"},{"C1", "Qsigma1", "Qalpha1", "C2", "Qsigma2", "Qalpha2", "C3", "Qsigma3", "Qalpha3", "R1"},{"R1", "Qsigma1", "Qalpha1", "C1", "R2","Qsigma2", "Qalpha2", "C2", "R3", "Qsigma3", "Qalpha3", "C3"},{"R1", "Qsigma1", "Qalpha1", "C1", "R2","Qsigma2", "Qalpha2", "C2", "R3", "Qsigma3", "Qalpha3", "C3", "R4"},{"R1", "Qsigma1", "Qalpha1", "C1", "R2","Qsigma2", "Qalpha2", "C2"},{"R1", "Qsigma1", "Qalpha1", "C1", "R2","Qsigma2", "Qalpha2", "C2", "R3"},{"R1", "Qsigma1", "Qalpha1", "R2", "Qsigma2", "Qalpha2", "R3", "Qsigma3", "Qalpha3", "R4", "C1"},{"R1", "Qsigma1", "Qalpha1", "R2", "C2", "R3", "Qsigma3", "Qalpha3", "R4", "C1"},{"R1", "Qsigma1", "Qalpha1", "R2", "C2", "R3", "Qsigma3", "Qalpha3", "R4"},{"R1", "Qsigma1", "Qalpha1", "R2", "Qsigma2", "Qalpha2", "R3", "Qsigma3", "Qalpha3", "R4", "C1"},{"R1", "Qsigma1", "Qalpha1", "R2", "Qsigma2", "Qalpha2", "R3", "C1"}}; + return compName[modelNumber]; + } + + + // Calculate the impedance of the listed model circuits + public static Complex modelImpedance(double[] parameter, double omega, int modelNumber){ + + Complex zVal = null; + Complex z1 = null; + Complex z2 = null; + Complex z3 = null; + Complex z4 = null; + switch(modelNumber){ + case 1: zVal = resistanceImpedance(parameter[0]); + break; + case 2: zVal = capacitanceImpedance(parameter[0], omega); + break; + case 3: zVal = inductanceImpedance(parameter[0], omega); + break; + case 4: zVal = infiniteWarburgImpedance(parameter[0], omega); + break; + case 5: zVal = finiteWarburgImpedance(parameter[0], parameter[1], omega); + break; + case 6: zVal = constantPhaseElementImpedance(parameter[0], parameter[1], omega); + break; + case 7: zVal = rInSeriesWithC(parameter[0], parameter[1], omega); + break; + case 8: zVal = new Complex(parameter[0], parameter[1]*omega); + break; + case 9: z1 = new Complex(0.0D, -1.0D/(parameter[0]*omega)); + z2 = new Complex(0.0D, parameter[1]*omega); + zVal = impedanceInSeries(z1, z2); + break; + case 10:zVal = rInParallelWithC(parameter[0], parameter[1], omega); + break; + case 11:z1 = new Complex(parameter[0], 0.0D); + z2 = new Complex(0.0D, parameter[1]*omega); + zVal = impedanceInParallel(z1, z2); + break; + case 12:z1 = new Complex(0.0D, -1.0D/(parameter[0]*omega)); + z2 = new Complex(0.0D, parameter[1]*omega); + zVal = impedanceInParallel(z1, z2); + break; + case 13:zVal = rInParallelWithC(parameter[0], parameter[1], omega); + zVal = zVal.plus(parameter[2]); + break; + case 14:zVal = rInParallelWithC(parameter[0], parameter[1], omega); + zVal = zVal.plus(parameter[2]); + z1 = new Complex(0.0D, parameter[3]*omega); + zVal = zVal.plus(z1); + break; + case 15:zVal = rInParallelWithC(parameter[0], parameter[1], omega); + zVal = zVal.plus(parameter[2]); + z1 = new Complex(0.0D, parameter[3]*omega); + zVal = impedanceInParallel(zVal, z1); + break; + case 16:zVal = rInParallelWithC(parameter[0], parameter[1], omega); + z2 = new Complex(0.0D, -1.0D/(parameter[2]*omega)); + zVal = zVal.plus(z2); + break; + case 17:z1 = new Complex(parameter[0], -1.0D/(parameter[1]*omega)); + z2 = new Complex(0.0D, -1.0D/(parameter[2]*omega)); + zVal = (z1.times(z2)).over(z2.plus(z1)); + break; + case 18:z1 = rInParallelWithC(parameter[0], parameter[1], omega); + z2 = new Complex(parameter[2], -1.0D/(parameter[3]*omega)); + zVal = z1.plus(z2); + break; + case 19:z1 = rInParallelWithC(parameter[0], parameter[1], omega); + z2 = rInParallelWithC(parameter[2], parameter[3], omega); + zVal = z1.plus(z2); + break; + case 20:z1 = rInParallelWithC(parameter[0], parameter[1], omega); + z2 = rInParallelWithC(parameter[2], parameter[3], omega); + zVal = z1.plus(z2); + zVal = zVal.plus(parameter[4]); + break; + case 21:z1 = rInParallelWithC(parameter[0], parameter[1], omega); + z2 = z1.plus(parameter[2]); + z3 = new Complex(0.0D, -1.0D/(parameter[3]*omega)); + z4 = impedanceInParallel(z2, z3); + zVal = z4.plus(parameter[4]); + break; + case 22:z1 = rInParallelWithC(parameter[0], parameter[1], omega); + z2 = rInParallelWithC(parameter[2], parameter[3], omega); + zVal = z1.plus(z2); + z3 = rInParallelWithC(parameter[4], parameter[5], omega); + zVal = zVal.plus(z3); + break; + case 23:z1 = rInParallelWithC(parameter[0], parameter[1], omega); + z2 = rInParallelWithC(parameter[2], parameter[3], omega); + zVal = z1.plus(z2); + z3 = rInParallelWithC(parameter[4], parameter[5], omega); + zVal = zVal.plus(z3); + zVal = zVal.plus(parameter[6]); + break; + case 24:z1 = infiniteWarburgImpedance(parameter[2], omega); + z2 = impedanceInSeries(parameter[0], z1); + z3 = capacitanceImpedance(parameter[1], omega); + z4 = impedanceInParallel(z2, z3); + zVal = impedanceInSeries(z4, parameter[3]); + break; + case 25:z1 = finiteWarburgImpedance(parameter[2], parameter[3], omega); + z2 = impedanceInSeries(parameter[0], z1); + z3 = capacitanceImpedance(parameter[1], omega); + z4 = impedanceInParallel(z2, z3); + zVal = impedanceInSeries(z4, parameter[4]); + break; + case 26:z1 = constantPhaseElementImpedance(parameter[2], parameter[3], omega); + z2 = impedanceInSeries(parameter[0], z1); + z3 = capacitanceImpedance(parameter[1], omega); + z4 = impedanceInParallel(z2, z3); + zVal = impedanceInSeries(z4, parameter[4]); + break; + case 27:z1 = rInParallelWithC(parameter[0], parameter[1], omega); + z2 = rInParallelWithC(parameter[2], parameter[3], omega); + zVal = z1.plus(z2); + z3 = infiniteWarburgImpedance(parameter[4], omega); + zVal = zVal.plus(z3); + break; + case 28:z1 = rInParallelWithC(parameter[0], parameter[1], omega); + z2 = rInParallelWithC(parameter[2], parameter[3], omega); + zVal = z1.plus(z2); + z3 = infiniteWarburgImpedance(parameter[4], omega); + z4 = new Complex(0.0D, -1.0D/(parameter[5]*omega)); + z4 = impedanceInParallel(z3, z4); + zVal = zVal.plus(z4); + zVal = zVal.plus(parameter[6]); + break; + case 29:z1 = rInParallelWithC(parameter[0], parameter[1], omega); + z2 = constantPhaseElementImpedance(parameter[3], parameter[4], omega); + z3 = impedanceInParallel(z2, parameter[2]); + zVal = z1.plus(z3); + break; + case 30:z1 = rInParallelWithC(parameter[0], parameter[1], omega); + z2 = constantPhaseElementImpedance(parameter[3], parameter[4], omega); + z3 = impedanceInParallel(z2, parameter[2]); + zVal = z1.plus(z3); + zVal = zVal.plus(parameter[5]); + break; + case 31:z1 = constantPhaseElementImpedance(parameter[1], parameter[2], omega); + zVal = impedanceInParallel(z1, parameter[0]); + z1 = constantPhaseElementImpedance(parameter[4], parameter[5], omega); + z2 = impedanceInParallel(z1, parameter[3]); + zVal = zVal.plus(z2); + z1 = constantPhaseElementImpedance(parameter[7], parameter[8], omega); + z2 = impedanceInParallel(z1, parameter[6]); + zVal = zVal.plus(z2); + break; + case 32:z1 = constantPhaseElementImpedance(parameter[1], parameter[2], omega); + zVal = impedanceInParallel(z1, parameter[0]); + z1 = constantPhaseElementImpedance(parameter[4], parameter[5], omega); + z2 = impedanceInParallel(z1, parameter[3]); + zVal = zVal.plus(z2); + z1 = constantPhaseElementImpedance(parameter[7], parameter[8], omega); + z2 = impedanceInParallel(z1, parameter[6]); + zVal = zVal.plus(z2); + zVal = zVal.plus(parameter[9]); + break; + case 33:z1 = constantPhaseElementImpedance(parameter[1], parameter[2], omega); + zVal = impedanceInParallel(z1, parameter[0]); + z1 = constantPhaseElementImpedance(parameter[4], parameter[5], omega); + z2 = impedanceInParallel(z1, parameter[3]); + zVal = zVal.plus(z2); + z1 = constantPhaseElementImpedance(parameter[7], parameter[8], omega); + z2 = impedanceInParallel(z1, parameter[6]); + zVal = zVal.plus(z2); + zVal = zVal.plus(parameter[9]); + z3 = new Complex(0.0D, -1.0D/(parameter[10]*omega)); + zVal = impedanceInParallel(zVal, z3); + break; + case 34:z1 = new Complex(0.0D, -1.0D/(parameter[0]*omega)); + z2 = constantPhaseElementImpedance(parameter[1], parameter[2], omega); + zVal = impedanceInParallel(z1, z2); + z1 = new Complex(0.0D, -1.0D/(parameter[3]*omega)); + z2 = constantPhaseElementImpedance(parameter[4], parameter[5], omega); + z3 = impedanceInParallel(z1, z2); + zVal = zVal.plus(z3); + z1 = new Complex(0.0D, -1.0D/(parameter[6]*omega)); + z2 = constantPhaseElementImpedance(parameter[7], parameter[8], omega); + z3 = impedanceInParallel(z1, z2); + zVal = zVal.plus(z3); + break; + case 35:z1 = new Complex(0.0D, -1.0D/(parameter[0]*omega)); + z2 = constantPhaseElementImpedance(parameter[1], parameter[2], omega); + zVal = impedanceInParallel(z1, z2); + z1 = new Complex(0.0D, -1.0D/(parameter[3]*omega)); + z2 = constantPhaseElementImpedance(parameter[4], parameter[5], omega); + z3 = impedanceInParallel(z1, z2); + zVal = zVal.plus(z3); + z1 = new Complex(0.0D, -1.0D/(parameter[6]*omega)); + z2 = constantPhaseElementImpedance(parameter[7], parameter[8], omega); + z3 = impedanceInParallel(z1, z2); + zVal = zVal.plus(z3); + zVal = zVal.plus(parameter[9]); + break; + case 36:z1 = constantPhaseElementImpedance(parameter[1], parameter[2], omega); + z2 = z1.plus(parameter[0]); + z3 = new Complex(0.0D, -1.0D/(parameter[3]*omega)); + zVal = impedanceInParallel(z2, z3); + z1 = constantPhaseElementImpedance(parameter[5], parameter[6], omega); + z2 = z1.plus(parameter[4]); + z3 = new Complex(0.0D, -1.0D/(parameter[7]*omega)); + z4 = impedanceInParallel(z2, z3); + zVal = zVal.plus(z4); + z1 = constantPhaseElementImpedance(parameter[9], parameter[10], omega); + z2 = z1.plus(parameter[8]); + z3 = new Complex(0.0D, -1.0D/(parameter[11]*omega)); + z4 = impedanceInParallel(z2, z3); + zVal = zVal.plus(z4); + break; + case 37:z1 = constantPhaseElementImpedance(parameter[1], parameter[2], omega); + z2 = z1.plus(parameter[0]); + z3 = new Complex(0.0D, -1.0D/(parameter[3]*omega)); + zVal = impedanceInParallel(z2, z3); + z1 = constantPhaseElementImpedance(parameter[5], parameter[6], omega); + z2 = z1.plus(parameter[4]); + z3 = new Complex(0.0D, -1.0D/(parameter[7]*omega)); + z4 = impedanceInParallel(z2, z3); + zVal = zVal.plus(z4); + z1 = constantPhaseElementImpedance(parameter[9], parameter[10], omega); + z2 = z1.plus(parameter[8]); + z3 = new Complex(0.0D, -1.0D/(parameter[11]*omega)); + z4 = impedanceInParallel(z2, z3); + zVal = zVal.plus(z4); + zVal = zVal.plus(parameter[12]); + break; + case 38:z1 = constantPhaseElementImpedance(parameter[1], parameter[2], omega); + z2 = z1.plus(parameter[0]); + z3 = new Complex(0.0D, -1.0D/(parameter[3]*omega)); + zVal = impedanceInParallel(z2, z3); + z1 = constantPhaseElementImpedance(parameter[5], parameter[6], omega); + z2 = z1.plus(parameter[4]); + z3 = new Complex(0.0D, -1.0D/(parameter[7]*omega)); + z4 = impedanceInParallel(z2, z3); + zVal = zVal.plus(z4); + break; + case 39:z1 = constantPhaseElementImpedance(parameter[1], parameter[2], omega); + z2 = z1.plus(parameter[0]); + z3 = new Complex(0.0D, -1.0D/(parameter[3]*omega)); + zVal = impedanceInParallel(z2, z3); + z1 = constantPhaseElementImpedance(parameter[5], parameter[6], omega); + z2 = z1.plus(parameter[4]); + z3 = new Complex(0.0D, -1.0D/(parameter[7]*omega)); + z4 = impedanceInParallel(z2, z3); + zVal = zVal.plus(z4); + zVal = z4.plus(parameter[8]); + break; + case 40:z1 = constantPhaseElementImpedance(parameter[1], parameter[2], omega); + zVal = impedanceInParallel(z1, parameter[0]); + z1 = constantPhaseElementImpedance(parameter[4], parameter[5], omega); + z2 = impedanceInParallel(z1, parameter[3]); + zVal = zVal.plus(z2); + z1 = constantPhaseElementImpedance(parameter[7], parameter[8], omega); + z2 = impedanceInParallel(z1, parameter[6]); + zVal = zVal.plus(z2); + z3 = new Complex(0.0D, -1.0D/(parameter[10]*omega)); + zVal = impedanceInParallel(zVal, z3); + zVal = zVal.plus(parameter[9]); + break; + case 41:z1 = constantPhaseElementImpedance(parameter[1], parameter[2], omega); + zVal = impedanceInParallel(z1, parameter[0]); + z1 = new Complex(0.0D, -1.0D/(parameter[4]*omega)); + z2 = impedanceInParallel(z1, parameter[3]); + zVal = zVal.plus(z2); + z1 = constantPhaseElementImpedance(parameter[6], parameter[7], omega); + z2 = impedanceInParallel(z1, parameter[5]); + zVal = zVal.plus(z2); + z3 = new Complex(0.0D, -1.0D/(parameter[9]*omega)); + zVal = impedanceInParallel(zVal, z3); + zVal = zVal.plus(parameter[8]); + break; + case 42:z1 = constantPhaseElementImpedance(parameter[1], parameter[2], omega); + zVal = impedanceInParallel(z1, parameter[0]); + z1 = new Complex(0.0D, -1.0D/(parameter[4]*omega)); + z2 = impedanceInParallel(z1, parameter[3]); + zVal = zVal.plus(z2); + z1 = constantPhaseElementImpedance(parameter[6], parameter[7], omega); + z2 = impedanceInParallel(z1, parameter[5]); + zVal = zVal.plus(z2); + zVal = zVal.plus(parameter[8]); + break; + case 43:z1 = constantPhaseElementImpedance(parameter[1], parameter[2], omega); + zVal = impedanceInParallel(z1, parameter[0]); + z1 = constantPhaseElementImpedance(parameter[4], parameter[5], omega); + z2 = impedanceInParallel(z1, parameter[3]); + zVal = zVal.plus(z2); + z1 = constantPhaseElementImpedance(parameter[7], parameter[8], omega); + z2 = impedanceInParallel(z1, parameter[6]); + zVal = zVal.plus(z2); + zVal = zVal.plus(parameter[9]); + z3 = new Complex(0.0D, -1.0D/(parameter[10]*omega)); + zVal = impedanceInParallel(zVal, z3); + break; + case 44:z1 = constantPhaseElementImpedance(parameter[1], parameter[2], omega); + zVal = impedanceInParallel(z1, parameter[0]); + z1 = constantPhaseElementImpedance(parameter[4], parameter[5], omega); + z2 = impedanceInParallel(z1, parameter[3]); + zVal = zVal.plus(z2); + zVal = zVal.plus(parameter[6]); + z3 = new Complex(0.0D, -1.0D/(parameter[7]*omega)); + zVal = impedanceInParallel(zVal, z3); + break; + default:throw new IllegalArgumentException("No model " + modelNumber + " exists"); + } + + return zVal; + } + + // returns the Warburg coefficient, sigma, - infinite diffusion layer + public static double warburgSigma(double electrodeArea, double oxidantDiffCoeff , double oxidantConcn, double reductantDiffCoeff, double reductantConcn, double tempCelsius, int electronsTransferred){ + double firstTerm = Fmath.R_GAS*(tempCelsius - Fmath.T_ABS)/(Fmath.square(electronsTransferred*Fmath.F_FARADAY)*electrodeArea*Math.sqrt(2)); + double secondTerm = 1.0D/(oxidantConcn*Math.sqrt(oxidantDiffCoeff)); + double thirdTerm = 1.0D/(reductantConcn*Math.sqrt(reductantDiffCoeff)); + return firstTerm*(secondTerm + thirdTerm); + } + + + // returns the capacitance of a parallel plate capacitor - plate width and length enterd + public static double parallelPlateCapacitance(double plateArea, double plateSeparation, double relativePermittivity){ + return plateArea*relativePermittivity*Fmath.EPSILON_0/plateSeparation; + } + // returns the capacitance of a parallel plate capacitor - plate area entered + public static double parallelPlateCapacitance(double plateLength, double plateWidth, double plateSeparation, double relativePermittivity){ + return plateLength*plateWidth*relativePermittivity*Fmath.EPSILON_0/plateSeparation; + } + + // returns the capacitance of coaxial cylinders, e.g. model of a coaxial cable + public static double coaxialCapacitance(double cylinderLength, double innerRadius, double outerRadius, double relativePermittivity){ + return 2.0D*Math.PI*relativePermittivity*Fmath.EPSILON_0*cylinderLength/Math.log(outerRadius/innerRadius); + } + + // returns the capacitance of parallel wires + public static double parallelWiresCapacitance(double wireLength, double wireRadius, double wireSeparation, double relativePermittivity){ + return Math.PI*relativePermittivity*Fmath.EPSILON_0*wireLength/Math.log((wireSeparation - wireRadius)/wireRadius); + } + + // returns the inductance of parallel plates - plate width and length entered + public static double parallelPlateInductance(double plateLength, double plateWidth, double plateSeparation, double relativePermeability){ + return relativePermeability*Fmath.MU_0*plateSeparation*plateLength/plateWidth; + } + + // returns the inductance of coaxial cylinders, e.g. model of a coaxial cable + public static double coaxialInductance(double cylinderLength, double innerRadius, double outerRadius, double relativePermeability){ + return relativePermeability*Fmath.MU_0*cylinderLength*Math.log(outerRadius/innerRadius)/(2.0D*Math.PI); + } + + // returns the inductance of parallel wires + public static double parallelWiresInductance(double wireLength, double wireRadius, double wireSeparation, double relativePermeability){ + return relativePermeability*Fmath.MU_0*wireLength*Math.log((wireSeparation - wireRadius)/wireRadius)/Math.PI; + } + + // returns the magnitude of a rectangular complex variable + public static double getMagnitude(Complex variable){ + return variable.abs(); + } + + // returns the argument (phase), in radians, of a rectangular complex variable + public static double getPhaseRad(Complex variable){ + return variable.argRad(); + } + + // returns the argument (phase), in degrees, of a rectangular complex variable + public static double getPhaseDeg(Complex variable){ + return variable.argDeg(); + } + + // converts magnitude and phase (radians) to a rectangular complex variable + public static Complex polarRad(double magnitude, double phase){ + Complex aa = new Complex(); + aa.polarRad(magnitude, phase); + return aa; + } + + // converts magnitude and phase (degrees) to a rectangular complex variable + public static Complex polarDeg(double magnitude, double phase){ + Complex aa = new Complex(); + aa.polarDeg(magnitude, phase); + return aa; + } + + // Converts frequency (Hz) to radial frequency + public static double frequencyToRadialFrequency(double frequency){ + return 2.0D*Math.PI*frequency; + } + + // Converts radial frequency to frequency (Hz) + public static double radialFrequencyToFrequency(double omega){ + return omega/(2.0D*Math.PI); + } + + // METAL WIRE/CABLE/PLATE RESISTANCES + // length = length in metres, area = cross-sectional + // area = area in square metres + // tempC = temptemperature in degrees Celsius + // Data from (1) Syed A Nasar, Electric Power Systems, Schaum's ouTlines, McGraw-Hill, 1990 + // (2) Handbook of Chemistry and Physics, Chemical Rubber Publishing Company, Cleveland, Ohio, 37th Edition, 1955 + + // Returns the resistance of aluminium + public static double resistanceAluminium(double length, double area, double tempC){ + double rho = 2.824e-8; // Al resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0039; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of aluminium + public static double resistanceAluminum(double length, double area, double tempC){ + double rho = 2.824e-8; // Al resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0039; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of hard drawn copper + public static double resistanceHardDrawnCopper(double length, double area, double tempC){ + double rho = 1.771e-8; // hard drawn Cu resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.00382; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of annealed copper + public static double resistanceAnnealedCopper(double length, double area, double tempC){ + double rho = 1.7241e-8; // annealed Cu resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.00393; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of 99.98% pure iron + public static double resistanceIron(double length, double area, double tempC){ + double rho = 10.0e-8; // Fe resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.005; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of manganese steel + public static double resistanceManganeseSteel(double length, double area, double tempC){ + double rho = 70.0e-8; // manganese steel resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.001; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of Siemens-Martin steel + public static double resistanceSiemensMartinSteel(double length, double area, double tempC){ + double rho = 18.0e-8; // Siemens-Martin steel resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.003; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of B. B. steel + public static double resistanceBBSteel(double length, double area, double tempC){ + double rho = 11.9e-8; // B. B. steel resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.004; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of E. B. B. steel + public static double resistanceEBBSteel(double length, double area, double tempC){ + double rho = 10.4e-8; // E. B. B. steel resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.005; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of brass + // Average value of a range of resistivities from 6.4 to 8.4 + public static double resistanceBrass(double length, double area, double tempC){ + double rho = 7.4e-8; // average brass resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.002; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of drawn tungsten + public static double resistanceDrawnTunsten(double length, double area, double tempC){ + double rho = 5.6e-8; // drawn tungsten resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0045; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of silver + public static double resistanceSilver(double length, double area, double tempC){ + double rho = 1.59e-8; // Ag resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0038; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of gold + public static double resistanceGold(double length, double area, double tempC){ + double rho = 2.84e-8; // Au resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0034; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of platinum + public static double resistancePlatinum(double length, double area, double tempC){ + double rho = 10.0e-8; // Pt resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.003; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of nickel + public static double resistanceNickel(double length, double area, double tempC){ + double rho = 7.8e-8; // Ni resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.006; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of drawn molybdenum + public static double resistanceMolybdenum(double length, double area, double tempC){ + double rho = 5.7e-8; // Mo resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.004; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of phosphor bronze + public static double resistancePhosphorBronze(double length, double area, double tempC){ + double rho = 11.0e-8; // phosphor bronze resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0033; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of tin + public static double resistanceTin(double length, double area, double tempC){ + double rho = 11.5e-8; // Sn resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0042; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of Nichrome + public static double resistanceNichrome(double length, double area, double tempC){ + double rho = 100.0e-8; // Nichrome resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0004; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of palladium + public static double resistancePalladium(double length, double area, double tempC){ + double rho = 11.0e-8; // Pd resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0033; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of tantalum + public static double resistanceTantalum(double length, double area, double tempC){ + double rho = 15.5e-8; // Ta resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0031; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of Therlo + public static double resistanceTherlo(double length, double area, double tempC){ + double rho = 47.0e-8; // Therlo resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.00001; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of Monel metal + public static double resistanceMonelMetal(double length, double area, double tempC){ + double rho = 42.0e-8; // Monel metal resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.002; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of manganan + public static double resistanceManganan(double length, double area, double tempC){ + double rho = 44.0e-8; // Ni resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.00001; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of constantan + public static double resistanceConstantan(double length, double area, double tempC){ + double rho = 49.0e-8; // Constantan resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.00001; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + + // Returns the resistance of antimony + public static double resistanceAntimony(double length, double area, double tempC){ + double rho = 41.7e-8; // Sb resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0036; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of cobalt + public static double resistanceCobalt(double length, double area, double tempC){ + double rho = 9.8e-8; // Co resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0033; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of magnesium + public static double resistanceMagnesium(double length, double area, double tempC){ + double rho = 4.6e-8; // Mg resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.004; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of zinc + public static double resistanceZinc(double length, double area, double tempC){ + double rho = 5.8e-8; // Zn resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0037; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of mercury + public static double resistanceMercury(double length, double area, double tempC){ + double rho = 95.738e-8; // Hg resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.00089; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of lead + public static double resistanceLead(double length, double area, double tempC){ + double rho = 22.0e-8; // Pb resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0039; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of German silver + public static double resistanceGermanSilver(double length, double area, double tempC){ + double rho = 33.0e-8; // German silver resistivity, ohms.metre, at 20 degrees Celsius + double alpha = 0.0004; // temperature coefficient, at 20 C, reciprocal degrees Celsius + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of material of restivity, rho, and temperature coefficient, alpha + public static double resistivityToResistance(double rho, double alpha, double length, double area, double tempC){ + double resistance20 = rho*length/area; + return resistance20*(1.0 + alpha*(tempC - 20.0)); + } + + // Returns the resistance of material of restivity, rho, + public static double resistivityToResistance(double rho, double length, double area){ + return rho*length/area; + } + + // Returns the resistivity of material of resistance, resistance + public static double resistanceToResistivity(double resistance, double length, double area){ + return resistance*area/length; + } +} diff --git a/src/main/java/flanagan/circuits/ParallelPlateLine.java b/src/main/java/flanagan/circuits/ParallelPlateLine.java new file mode 100755 index 0000000000000000000000000000000000000000..ef53197c41fc643b1393db7afc59cd45385e65dc --- /dev/null +++ b/src/main/java/flanagan/circuits/ParallelPlateLine.java @@ -0,0 +1,310 @@ +/* Class ParallelPlateLine +* +* Models a parallel plate transmision line +* This is a subclass of the superclass TransmissionLine +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: July 2007 +* UPDATE: 7 April 2008 +* +* DOCUMENTATION: +* See Michael T Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ParallelPlateLine.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/TransmissionLine.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2007 - 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.circuits; + +import flanagan.complex.Complex; + +public class ParallelPlateLine extends TransmissionLine{ + + private double plateWidth = -1.0D; // plate width + private double plateSeparation = -1.0D; // plate separation - inner surface to inner surface + private boolean distancesSet = false; // = true when both plate width and separation entered + + private double relativePermittivity = 1.0D; // relative electrical permittivity of the material between the conductors + private double relativePermeability = 1.0D; // relative magnetic permeability of the material between the conductors + + + // CONSTRUCTOR + // Default constructor + public ParallelPlateLine(){ + super.title = "Parallel Plate Line"; + } + + // Constructor with user suppled title + public ParallelPlateLine(String title){ + super.title = title; + } + + // PLATE WIDTH + // Set plate width + public void setPlateWidth(double width){ + if(width<=0.0D)throw new IllegalArgumentException("The plate width, " + width + ", must be greater than zero"); + this.plateWidth = width; + if(this.plateSeparation!=-1.0)this.distancesSet = true; + if(this.distancesSet)this.calculateDistributedCapacitanceAndInductance(); + } + + // PLATE SEPARATION + // Set plate separation - inner surface to inner surface + public void setPlateSeparation(double separation){ + if(separation<=0.0D)throw new IllegalArgumentException("The plate separation, " + separation + ", must be greater than zero"); + this.plateSeparation = separation; + if(this.plateWidth!=-1.0)this.distancesSet = true; + if(this.distancesSet)this.calculateDistributedCapacitanceAndInductance(); + } + + // PERMITTIVITY + // Set relative electrical permittivity of the material between the conductors + public void setRelativePermittivity(double epsilonR){ + this.relativePermittivity = epsilonR; + if(this.distancesSet)this.calculateDistributedCapacitanceAndInductance(); + } + + // PERMEABILTY + // Set relative magnetic permeability of the material between the conductors + public void setRelativePermeability(double muR){ + this.relativePermeability = muR; + if(this.distancesSet)this.calculateDistributedCapacitanceAndInductance(); + } + + // CALCULATE DISTRIBUTED PARAMETERS + private void calculateDistributedCapacitanceAndInductance(){ + super.distributedCapacitance = Impedance.parallelPlateCapacitance(1.0D, this.plateWidth, this.plateSeparation, this.relativePermittivity); + super.distributedInductance = Impedance.parallelPlateInductance(1.0D, this.plateWidth, this.plateSeparation, this.relativePermeability); + } + + + // DEEP COPY + public ParallelPlateLine copy(){ + + if(this==null){ + return null; + } + else{ + ParallelPlateLine tl = new ParallelPlateLine(); + + tl.plateWidth = this.plateWidth; + tl.plateSeparation = this.plateSeparation; + tl.distancesSet = this.distancesSet; + tl.relativePermittivity = this.relativePermittivity; + tl.relativePermeability = this.relativePermeability; + + tl.title = this.title; + tl.distributedResistance = this.distributedResistance; + tl.distributedConductance = this.distributedConductance; + tl.distributedCapacitance = this.distributedCapacitance; + tl.distributedInductance = this.distributedInductance; + + tl.distributedImpedance = this.distributedImpedance.copy(); + tl.distributedAdmittance = this.distributedAdmittance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.lineLength = this.lineLength; + tl.segmentLength = this.segmentLength; + tl.frequency = this.frequency; + tl.segmentLength = this.segmentLength; + tl.omega = this.omega; + + tl.inputVoltage = this.inputVoltage.copy(); + tl.inputCurrent = this.inputCurrent.copy(); + tl.outputVoltage = this.outputVoltage.copy(); + tl.outputCurrent = this.outputCurrent.copy(); + + tl.idealWavelength = this.idealWavelength; + tl.generalWavelength = this.generalWavelength; + tl.lowLossWavelength = this.lowLossWavelength; + + tl.idealPhaseVelocity = this.idealPhaseVelocity; + tl.generalPhaseVelocity = this.generalPhaseVelocity; + tl.lowLossPhaseVelocity = this.lowLossPhaseVelocity; + + tl.idealGroupVelocity = this.idealGroupVelocity; + tl.generalGroupVelocity = this.generalGroupVelocity; + tl.lowLossGroupVelocity = this.lowLossGroupVelocity; + tl.delta = this.delta; + + tl.idealAttenuationConstant = this.idealAttenuationConstant; + tl.generalAttenuationConstant = this.generalAttenuationConstant; + tl.lowLossAttenuationConstant = this.lowLossAttenuationConstant; + + tl.idealPhaseConstant = this.idealPhaseConstant; + tl.generalPhaseConstant = this.generalPhaseConstant; + tl.lowLossPhaseConstant = this.lowLossPhaseConstant; + + tl.idealPropagationConstant = this.idealPropagationConstant.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.generalPropagationConstant = this.generalPropagationConstant.copy(); + tl.lowLossPropagationConstant = this.lowLossPropagationConstant.copy(); + tl.idealCharacteristicImpedance = this.idealCharacteristicImpedance.copy(); + tl.idealRealCharacteristicImpedance = this.idealRealCharacteristicImpedance; + + tl.generalCharacteristicImpedance = this.generalCharacteristicImpedance.copy(); + tl.lowLossCharacteristicImpedance = this.lowLossCharacteristicImpedance.copy(); + tl.idealInputImpedance = this.idealInputImpedance.copy(); + tl.generalInputImpedance = this.generalInputImpedance.copy(); + tl.lowLossInputImpedance = this.lowLossInputImpedance.copy(); + + tl.idealShortedLineImpedance = this.idealShortedLineImpedance.copy(); + tl.generalShortedLineImpedance = this.generalShortedLineImpedance.copy(); + tl.lowLossShortedLineImpedance = this.lowLossShortedLineImpedance.copy(); + + tl.idealOpenLineImpedance = this.idealOpenLineImpedance.copy(); + tl.generalOpenLineImpedance = this.generalOpenLineImpedance.copy(); + tl.lowLossOpenLineImpedance = this.lowLossOpenLineImpedance.copy(); + + tl.idealQuarterWaveLineImpedance = this.idealQuarterWaveLineImpedance.copy(); + tl.generalQuarterWaveLineImpedance = this.generalQuarterWaveLineImpedance.copy(); + tl.lowLossQuarterWaveLineImpedance = this.lowLossQuarterWaveLineImpedance.copy(); + + tl.idealHalfWaveLineImpedance = this.idealHalfWaveLineImpedance.copy(); + tl.generalHalfWaveLineImpedance = this.generalHalfWaveLineImpedance.copy(); + tl.lowLossHalfWaveLineImpedance = this.lowLossHalfWaveLineImpedance.copy(); + + tl.idealRefectionCoefficient = this.idealRefectionCoefficient.copy(); + tl.generalRefectionCoefficient = this.generalRefectionCoefficient.copy(); + tl.lowLossRefectionCoefficient = this.lowLossRefectionCoefficient.copy(); + + tl.idealStandingWaveRatio = this.idealStandingWaveRatio; + tl.generalStandingWaveRatio = this.generalStandingWaveRatio; + tl.lowLossStandingWaveRatio = this.lowLossStandingWaveRatio; + + tl.idealABCDmatrix = this.idealABCDmatrix.copy(); + tl.generalABCDmatrix = this.generalABCDmatrix.copy(); + tl.lowLossABCDmatrix = this.lowLossABCDmatrix.copy(); + + tl.numberOfPoints = this.numberOfPoints; + + return tl; + } + } + + + // Clone - overrides Java.Object method clone + public Object clone(){ + + Object ret = null; + + if(this!=null){ + + ParallelPlateLine tl = new ParallelPlateLine(); + + tl.plateWidth = this.plateWidth; + tl.plateSeparation = this.plateSeparation; + tl.distancesSet = this.distancesSet; + tl.relativePermittivity = this.relativePermittivity; + tl.relativePermeability = this.relativePermeability; + + tl.title = this.title; + tl.distributedResistance = this.distributedResistance; + tl.distributedConductance = this.distributedConductance; + tl.distributedCapacitance = this.distributedCapacitance; + tl.distributedInductance = this.distributedInductance; + + tl.distributedImpedance = this.distributedImpedance.copy(); + tl.distributedAdmittance = this.distributedAdmittance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.lineLength = this.lineLength; + tl.segmentLength = this.segmentLength; + tl.frequency = this.frequency; + tl.segmentLength = this.segmentLength; + tl.omega = this.omega; + + tl.inputVoltage = this.inputVoltage.copy(); + tl.inputCurrent = this.inputCurrent.copy(); + tl.outputVoltage = this.outputVoltage.copy(); + tl.outputCurrent = this.outputCurrent.copy(); + + tl.idealWavelength = this.idealWavelength; + tl.generalWavelength = this.generalWavelength; + tl.lowLossWavelength = this.lowLossWavelength; + + tl.idealPhaseVelocity = this.idealPhaseVelocity; + tl.generalPhaseVelocity = this.generalPhaseVelocity; + tl.lowLossPhaseVelocity = this.lowLossPhaseVelocity; + + tl.idealGroupVelocity = this.idealGroupVelocity; + tl.generalGroupVelocity = this.generalGroupVelocity; + tl.lowLossGroupVelocity = this.lowLossGroupVelocity; + tl.delta = this.delta; + + tl.idealAttenuationConstant = this.idealAttenuationConstant; + tl.generalAttenuationConstant = this.generalAttenuationConstant; + tl.lowLossAttenuationConstant = this.lowLossAttenuationConstant; + + tl.idealPhaseConstant = this.idealPhaseConstant; + tl.generalPhaseConstant = this.generalPhaseConstant; + tl.lowLossPhaseConstant = this.lowLossPhaseConstant; + + tl.idealPropagationConstant = this.idealPropagationConstant.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.generalPropagationConstant = this.generalPropagationConstant.copy(); + tl.lowLossPropagationConstant = this.lowLossPropagationConstant.copy(); + tl.idealCharacteristicImpedance = this.idealCharacteristicImpedance.copy(); + tl.idealRealCharacteristicImpedance = this.idealRealCharacteristicImpedance; + + tl.generalCharacteristicImpedance = this.generalCharacteristicImpedance.copy(); + tl.lowLossCharacteristicImpedance = this.lowLossCharacteristicImpedance.copy(); + tl.idealInputImpedance = this.idealInputImpedance.copy(); + tl.generalInputImpedance = this.generalInputImpedance.copy(); + tl.lowLossInputImpedance = this.lowLossInputImpedance.copy(); + + tl.idealShortedLineImpedance = this.idealShortedLineImpedance.copy(); + tl.generalShortedLineImpedance = this.generalShortedLineImpedance.copy(); + tl.lowLossShortedLineImpedance = this.lowLossShortedLineImpedance.copy(); + + tl.idealOpenLineImpedance = this.idealOpenLineImpedance.copy(); + tl.generalOpenLineImpedance = this.generalOpenLineImpedance.copy(); + tl.lowLossOpenLineImpedance = this.lowLossOpenLineImpedance.copy(); + + tl.idealQuarterWaveLineImpedance = this.idealQuarterWaveLineImpedance.copy(); + tl.generalQuarterWaveLineImpedance = this.generalQuarterWaveLineImpedance.copy(); + tl.lowLossQuarterWaveLineImpedance = this.lowLossQuarterWaveLineImpedance.copy(); + + tl.idealHalfWaveLineImpedance = this.idealHalfWaveLineImpedance.copy(); + tl.generalHalfWaveLineImpedance = this.generalHalfWaveLineImpedance.copy(); + tl.lowLossHalfWaveLineImpedance = this.lowLossHalfWaveLineImpedance.copy(); + + tl.idealRefectionCoefficient = this.idealRefectionCoefficient.copy(); + tl.generalRefectionCoefficient = this.generalRefectionCoefficient.copy(); + tl.lowLossRefectionCoefficient = this.lowLossRefectionCoefficient.copy(); + + tl.idealStandingWaveRatio = this.idealStandingWaveRatio; + tl.generalStandingWaveRatio = this.generalStandingWaveRatio; + tl.lowLossStandingWaveRatio = this.lowLossStandingWaveRatio; + + tl.idealABCDmatrix = this.idealABCDmatrix.copy(); + tl.generalABCDmatrix = this.generalABCDmatrix.copy(); + tl.lowLossABCDmatrix = this.lowLossABCDmatrix.copy(); + + tl.numberOfPoints = this.numberOfPoints; + + ret = (Object)tl; + } + return ret; + } +} diff --git a/src/main/java/flanagan/circuits/Phasor.java b/src/main/java/flanagan/circuits/Phasor.java new file mode 100755 index 0000000000000000000000000000000000000000..ec4b1ac179d97d83ecbd279fa63a65be9d6ce7fc --- /dev/null +++ b/src/main/java/flanagan/circuits/Phasor.java @@ -0,0 +1,1777 @@ +/* +* Class Phasor +* +* Defines a Phasor and includes +* the methods needed for standard Phasor arithmetic +* +* See PhasorMatrix for creation and manipulatioin of matrices of phasors +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 4 July 2007 +* AMENDED: 17 april 2008 +* +* DOCUMENTATION: +* See Michael T Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* http://www.ee.ucl.ac.uk/~mflanaga/java/Phasor.html +* +* Copyright (c) 2007 - 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.circuits; + +import flanagan.complex.Complex; +import flanagan.math.Fmath; + +public class Phasor{ + + private double magnitude = 0.0D; // magnitude of the Phasor + private double phaseInDeg = 0.0D; // phase of the Phasor in degrees + private double phaseInRad = 0.0D; // phase of the Phasor in degrees + private Complex rectangular = new Complex(0.0, 0.0); // rectangular complex equivalent of the Phasor + + // frequency - static to prevent inappropriate combination of phasors + private static double frequency = Double.NaN; // frequency in Hz + private static double omega = Double.NaN; // radial frequency + + + + // CONSTRUCTORS + // default constructor + public Phasor(){ + } + + // Constructor setting magnitude and phase in degrees + public Phasor(double magnitude, double phase){ + this.magnitude = magnitude; + this.phaseInDeg = phase; + this.phaseInRad = Math.toRadians(phase); + this.rectangular.polar(this.magnitude, this.phaseInRad); + } + + // Constructor setting magnitude only + public Phasor(double magnitude){ + this.magnitude = magnitude; + this.rectangular.polar(this.magnitude, this.phaseInRad); + } + + // SET VALUES + // Set the frequency in Hz - as a static variable + public static void setFrequency(double freq){ + if(Fmath.isNaN(Phasor.frequency)){ + Phasor.frequency = freq; + Phasor.omega = 2.0D*Math.PI*freq; + + } + else{ + throw new IllegalArgumentException("You have already entered a value for the frequency, " + Phasor.frequency + ", that differs from the one you are now attempting to enter, " + freq); + } + } + + // Set the radial frequency - as a static variable + public static void setRadialFrequency(double omega){ + if(Fmath.isNaN(Phasor.omega)){ + Phasor.omega = omega; + Phasor.frequency = Phasor.omega/(2.0D*Math.PI); + } + else{ + throw new IllegalArgumentException("You have already entered a value for the radial frequency, omega, " + Phasor.omega + ", that differs from the one you are now attempting to enter, " + omega); + } + } + + // Set the value of magnitude + public void setMagnitude(double magnitude){ + this.magnitude = magnitude; + this.rectangular.polar(this.magnitude, this.phaseInRad); + } + + // Set the value of phase in degrees + public void setPhaseInDegrees(double phase){ + this.phaseInDeg = phase; + this.phaseInRad = Math.toRadians(phase); + this.rectangular.polar(this.magnitude, this.phaseInRad); + } + + + // Set the values of magnitude and phase in degrees + public void reset(double magnitude, double phaseInDegrees){ + this.magnitude = magnitude; + this.phaseInDeg = phaseInDegrees; + this.phaseInRad = Math.toRadians(phaseInDegrees); + this.rectangular.polar(this.magnitude, this.phaseInRad); + } + + + // GET VALUES + // Get the frequency in Hz + public static double getFrequency(){ + return Phasor.frequency; + } + + // Get the radial frequency + public static double setRadialFrequency(){ + return Phasor.omega; + } + + // Get the value of magnitude + public double getMagnitude(){ + return this.magnitude; + } + + // Get the value of phase in degrees + public double getPhaseInDegrees(){ + return this.phaseInDeg; + } + + // Get the value of phase in radians + public double getPhaseInRadians(){ + return this.phaseInRad; + } + + // Get the real part of the Phasor + public double getReal(){ + return this.magnitude*Math.cos(this.phaseInRad); + } + + // Get the imaginary part of the Phasor + public double getImag(){ + return this.magnitude*Math.sin(this.phaseInRad); + } + + // CONVERSIONS + + // converts rectangular complex variable to a Phasor + public static Phasor toPhasor(Complex cc){ + Phasor ph = new Phasor(); + ph.magnitude = cc.abs(); + ph.phaseInRad = cc.argRad(); + ph.phaseInDeg = cc.argDeg(); + ph.rectangular = cc; + return ph; + } + + // converts the Phasor to a rectangular complex variable + public Complex toRectangular(){ + Complex cc = new Complex(); + cc.polar(this.magnitude, this.phaseInRad); + return cc; + } + + // converts the Phasor to a rectangular complex variable - static method + public static Complex toRectangular(Phasor ph){ + Complex cc = new Complex(); + cc.polar(ph.magnitude, ph.phaseInRad); + return cc; + } + + // converts the Phasor to a rectangular complex variable + public Complex toComplex(){ + Complex cc = new Complex(); + cc.polar(this.magnitude, this.phaseInRad); + return cc; + } + + // converts the Phasor to a rectangular complex variable - static method + public static Complex toComplex(Phasor ph){ + Complex cc = new Complex(); + cc.polar(ph.magnitude, ph.phaseInRad); + return cc; + } + + // Format a phasor number as a string, 'magnitude''<''phase''deg' - phase in degrees + // Overides java.lang.String.toString() + // instance method + public String toString(){ + return this.magnitude + "<" + this.phaseInDeg + "deg"; + } + + // Format a phasor number as a string, 'magnitude''<''phase''deg' - phase in degrees + // Overides java.lang.String.toString() + // static method + public static String toString(Phasor ph){ + return ph.magnitude + "<" + ph.phaseInDeg + "deg"; + } + + + // Parse a string to obtain Phasor + // accepts strings: + // 'magnitude''<''phase' - phase in degrees + // 'magnitude''L''phase' - phase in degrees + // 'magnitude''<''phase''deg' - phase in degrees + // 'magnitude''L''phase''deg' - phase in degrees + // 'magnitude''<''phase''rad' - phase in radians + // 'magnitude''L''phase''rad' - phase in radians + public static Phasor parsePhasor(String ss){ + Phasor ph = new Phasor(); + ss = ss.trim(); + int anglePos = ss.indexOf('<'); + if(anglePos==-1){ + anglePos = ss.indexOf('L'); + if(anglePos==-1)throw new IllegalArgumentException("no angle symbol, <, in the string, ss"); + } + int degPos = ss.indexOf('d'); + if(degPos==-1)degPos = ss.indexOf('D'); + int radPos = ss.indexOf('r'); + if(radPos==-1)degPos = ss.indexOf('R'); + String mag = ss.substring(0,anglePos); + ph.magnitude = Double.parseDouble(mag); + String phas = null; + if(degPos!=-1){ + phas = ss.substring(anglePos+1, degPos); + ph.phaseInDeg = Double.parseDouble(mag); + ph.phaseInRad = Math.toRadians(ph.phaseInDeg); + } + if(degPos==-1 && radPos==-1){ + phas = ss.substring(anglePos+1); + ph.phaseInDeg = Double.parseDouble(phas); + ph.phaseInRad = Math.toRadians(ph.phaseInDeg); + } + if(radPos!=-1){ + phas = ss.substring(anglePos+1, radPos); + ph.phaseInRad = Double.parseDouble(phas); + ph.phaseInDeg = Math.toDegrees(ph.phaseInRad); + } + ph.rectangular.polar(ph.magnitude, ph.phaseInRad); + + return ph; + } + + // Same method as parsePhasor + // Overides java.lang.Object.valueOf() + public static Phasor valueOf(String ss){ + return Phasor.parsePhasor(ss); + } + + // INPUT AND OUTPUT + + // READ A PHASOR + // Read a Phasor from the keyboard console after a prompt message + // in a String format compatible with Phasor.parse, + // 'magnitude'<'phase', 'magnitude'<'phase'deg, 'magnitude'<'phase'rad + // e.g. 1.23<34.1deg, -0.67<-56.7, 6.8e2<-0.22rad + // prompt = Prompt message to vdu + public static final synchronized Phasor readPhasor(String prompt){ + int ch = ' '; + String phstring = ""; + boolean done = false; + + System.out.print(prompt + " "); + System.out.flush(); + + while (!done){ + try{ + ch = System.in.read(); + if (ch < 0 || (char)ch == '\n') + done = true; + else + phstring = phstring + (char) ch; + } + catch(java.io.IOException e){ + done = true; + } + } + return Phasor.parsePhasor(phstring); + } + + // Read a Phasor from the keyboard console after a prompt message (with String default option) + // in a String format compatible with Phasor.parse, + // 'magnitude'<'phase', 'magnitude'<'phase'deg, 'magnitude'<'phase'rad + // e.g. 1.23<34.1deg, -0.67<-56.7, 6.8e2<-0.22rad + // prompt = Prompt message to vdu + // dflt = default value + public static final synchronized Phasor readPhasor(String prompt, String dflt){ + int ch = ' '; + String phstring = ""; + boolean done = false; + + System.out.print(prompt + " [default value = " + dflt + "] "); + System.out.flush(); + + int i=0; + while (!done){ + try{ + ch = System.in.read(); + if (ch < 0 || (char)ch == '\n' || (char)ch =='\r'){ + if(i==0){ + phstring = dflt; + if((char)ch == '\r')ch = System.in.read(); + } + done = true; + } + else{ + phstring = phstring + (char) ch; + i++; + } + } + catch(java.io.IOException e){ + done = true; + } + } + return Phasor.parsePhasor(phstring); + } + + // Read a Phasor from the keyboard console after a prompt message (with Phasor default option) + // in a String format compatible with Phasor.parse, + // 'magnitude'<'phase', 'magnitude'<'phase'deg, 'magnitude'<'phase'rad + // e.g. 1.23<34.1deg, -0.67<-56.7, 6.8e2<-0.22rad + // prompt = Prompt message to vdu + // dflt = default value + public static final synchronized Phasor readPhasor(String prompt, Phasor dflt) + { + int ch = ' '; + String phstring = ""; + boolean done = false; + + System.out.print(prompt + " [default value = " + dflt + "] "); + System.out.flush(); + + int i=0; + while (!done){ + try{ + ch = System.in.read(); + if (ch < 0 || (char)ch == '\n' || (char)ch =='\r'){ + if(i==0){ + if((char)ch == '\r')ch = System.in.read(); + return dflt; + } + done = true; + } + else{ + phstring = phstring + (char) ch; + i++; + } + } + catch(java.io.IOException e){ + done = true; + } + } + return Phasor.parsePhasor(phstring); + } + + // Read a Phasor from the keyboard console without a prompt message + // in a String format compatible with Phasor.parse, + // 'magnitude'<'phase', 'magnitude'<'phase'deg, 'magnitude'<'phase'rad + // e.g. 1.23<34.1deg, -0.67<-56.7, 6.8e2<-0.22rad + public static final synchronized Phasor readPhasor(){ + int ch = ' '; + String phstring = ""; + boolean done = false; + + System.out.print(" "); + System.out.flush(); + + while (!done){ + try{ + ch = System.in.read(); + if (ch < 0 || (char)ch == '\n') + done = true; + else + phstring = phstring + (char) ch; + } + catch(java.io.IOException e){ + done = true; + } + } + return Phasor.parsePhasor(phstring); + } + + + // PRINT A PHASOR + // Print to terminal window with text (message) and a line return + public void println(String message){ + System.out.println(message + " " + this.toString()); + } + + // Print to terminal window without text (message) but with a line return + public void println(){ + System.out.println(" " + this.toString()); + } + + // Print to terminal window with text (message) but without line return + public void print(String message){ + System.out.print(message + " " + this.toString()); + } + + // Print to terminal window without text (message) and without line return + public void print(){ + System.out.print(" " + this.toString()); + } + + // PRINT AN ARRAY OF PHASORS + // Print an array to terminal window with text (message) and a line return + public static void println(String message, Phasor[] aa){ + System.out.println(message); + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i].toString() + " "); + } + } + + // Print an array to terminal window without text (message) but with a line return + public static void println(Phasor[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i].toString() + " "); + } + } + + // Print an array to terminal window with text (message) but no line returns except at the end + public static void print(String message, Phasor[] aa){ + System.out.print(message+ " "); + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i].toString() + " "); + } + System.out.println(); + } + + // Print an array to terminal window without text (message) but with no line returns except at the end + public static void print(Phasor[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i].toString() + " "); + } + System.out.println(); + } + + // TRUNCATION + // Rounds the mantissae of both the magnitude and phase to prec places - instance + public Phasor truncate(int prec){ + if(prec<0)return this; + + double xMa = this.magnitude; + double xPd = this.phaseInDeg; + double xPr = this.phaseInRad; + Complex xRect = this.rectangular; + + Phasor y = new Phasor(); + + y.magnitude = Fmath.truncate(xMa, prec); + y.phaseInDeg = Fmath.truncate(xPd, prec); + y.phaseInRad = Fmath.truncate(xPr, prec); + y.rectangular = Complex.truncate(xRect, prec); + + return y; + } + + // Rounds the mantissae of both the magnitude and phase to prec places - static + public static Phasor truncate(Phasor ph, int prec){ + if(prec<0)return ph; + + double xMa = ph.magnitude; + double xPd = ph.phaseInDeg; + double xPr = ph.phaseInRad; + Complex xRect = ph.rectangular; + + Phasor y = new Phasor(); + + y.magnitude = Fmath.truncate(xMa, prec); + y.phaseInDeg = Fmath.truncate(xPd, prec); + y.phaseInRad = Fmath.truncate(xPr, prec); + y.rectangular = Complex.truncate(xRect, prec); + + return y; + } + + + // HASH CODE + + // Return a HASH CODE for the Phasor + // Overides java.lang.Object.hashCode() + public int hashCode(){ + long lmagnt = Double.doubleToLongBits(this.magnitude); + long lphase = Double.doubleToLongBits(this.phaseInDeg); + int hmagnt = (int)(lmagnt^(lmagnt>>>32)); + int hphase = (int)(lphase^(lphase>>>32)); + return 6*(hmagnt/10)+4*(hphase/10); + } + + + // ARRAYS + + // Create a one dimensional array of Phasors of length n + // all magnitudes = 1 and all phases = 0 + public static Phasor[] oneDarray(int n){ + Phasor[] a = new Phasor[n]; + Phasor b = new Phasor(); + b.reset(1.0, 0.0); + for(int i=0; i<n; i++){ + a[i] = b; + } + return a; + } + + // Create a one dimensional array of Phasor objects of length n + // all magnitudes = a and all phases = b + public static Phasor[] oneDarray(int n, double a, double b){ + Phasor[] phArray = new Phasor[n]; + Phasor ph = new Phasor(); + ph.reset(a, b); + for(int i=0; i<n; i++){ + phArray[i] = ph; + } + return phArray; + } + + + // Create a one dimensional array of Phasors of length n + // all = the Phasor constant + public static Phasor[] oneDarray(int n, Phasor constant){ + Phasor[] ph =new Phasor[n]; + for(int i=0; i<n; i++){ + ph[i] = constant.copy(); + } + return ph; + } + + // Create a two dimensional array of Phasors of dimensions n and m + // all magnitudes = unity and all phases = zero + public static Phasor[][] twoDarray(int n, int m){ + Phasor[][] phArray = new Phasor[n][m]; + Phasor ph = new Phasor(); + ph.reset(1.0, 0.0); + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + phArray[i][j] = ph; + } + } + return phArray; + } + + // Create a two dimensional array of Phasors of dimensions n and m + // all magnitudes = a and all phases = b + public static Phasor[][] twoDarray(int n, int m, double a, double b){ + Phasor[][] phArray = new Phasor[n][m]; + Phasor ph = new Phasor(); + ph.reset(a, b); + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + phArray[i][j] = ph; + } + } + return phArray; + } + + // Create a two dimensional array of Phasors of dimensions n and m + // all = the Phasor constant + public static Phasor[][] twoDarray(int n, int m, Phasor constant){ + Phasor[][]phArray =new Phasor[n][m]; + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + phArray[i][j] = constant.copy(); + } + } + return phArray; + + } + + // Create a three dimensional array of Phasorss of dimensions n, m and l + // all magnitudes = unity and all phaes = zero + public static Phasor[][][] threeDarray(int n, int m, int l){ + Phasor[][][] phArray = new Phasor[n][m][l]; + Phasor ph = new Phasor(); + ph.reset(1.0, 0.0); + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + for(int k=0; k<l; k++){ + phArray[i][j][k] = ph; + } + } + } + return phArray; + } + + // Create a three dimensional array of Phasorss of dimensions n, m and l + // all magnitudes = a and all phases = b + public static Phasor[][][] threeDarray(int n, int m, int l, double a, double b){ + Phasor[][][] phArray = new Phasor[n][m][l]; + Phasor ph = new Phasor(); + ph.reset(a, b); + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + for(int k=0; k<l; k++){ + phArray[i][j][k] = ph; + } + } + } + return phArray; + } + + // Create a three dimensional array of Phasors of dimensions n, m and l + // all = the Phasor constant + public static Phasor[][][] threeDarray(int n, int m, int l, Phasor constant){ + Phasor[][][] phArray = new Phasor[n][m][l]; + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + for(int k=0; k<l; k++){ + phArray[i][j][k] = constant.copy(); + } + } + } + return phArray; + } + + // COPY + + // Copy a single Phasor [instance method] + public Phasor copy(){ + if(this==null){ + return null; + } + else{ + Phasor b = new Phasor(); + b.magnitude = this.magnitude; + b.phaseInDeg = this.phaseInDeg; + b.phaseInRad = this.phaseInRad; + return b; + } + } + + // Copy a single Phasor [static method] + public static Phasor copy(Phasor ph){ + if(ph==null){ + return null; + } + else{ + Phasor b = new Phasor(); + b.magnitude = ph.magnitude; + b.phaseInDeg = ph.phaseInDeg; + b.phaseInRad = ph.phaseInRad; + return b; + } + } + + // Copy a 1D array of Phasors (deep copy) + public static Phasor[] copy(Phasor[] a){ + if(a==null){ + return null; + } + else{ + int n =a.length; + Phasor[] b = Phasor.oneDarray(n); + for(int i=0; i<n; i++){ + b[i] = a[i].copy(); + } + return b; + } + } + + // Copy a 2D array of Phasors (deep copy) + public static Phasor[][] copy(Phasor[][] a){ + if(a==null){ + return null; + } + else{ + int n =a.length; + int m =a[0].length; + Phasor[][] b = Phasor.twoDarray(n, m); + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + b[i][j] = a[i][j].copy(); + } + } + return b; + } + } + + // Copy a 3D array of Phasors (deep copy) + public static Phasor[][][] copy(Phasor[][][] a){ + if(a==null){ + return null; + } + else{ + int n = a.length; + int m = a[0].length; + int l = a[0][0].length; + Phasor[][][] b = Phasor.threeDarray(n, m, l); + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + for(int k=0; k<l; k++){ + b[i][j][k] = a[i][j][k].copy(); + } + } + } + return b; + } + } + + // CLONE + // Overrides Java.Object method clone + // Copy a single Phasor + public Object clone(){ + Object ret = null; + + if(this!=null){ + Phasor b = new Phasor(); + b.magnitude = this.magnitude; + b.phaseInDeg = this.phaseInDeg; + b.phaseInRad = this.phaseInRad; + ret = (Object)b; + } + + return ret; + } + + // ADDITION + + // Add a Phasor to this Phasor + // this Phasor remains unaltered + public Phasor plus(Phasor ph){ + Complex com1 = this.toRectangular(); + Complex com2 = ph.toRectangular(); + Complex com3 = com1.plus(com2); + return Phasor.toPhasor(com3); + } + + // Add a complex number to this Phasor + // this Phasor remains unaltered + public Phasor plus(Complex com1){ + Phasor ph = new Phasor(); + Complex com2 = this.toRectangular(); + Complex com3 = com1.plus(com2); + return Phasor.toPhasor(com3); + } + + // Add a Phasor to this Phasor and replace this with the sum + public void plusEquals(Phasor ph1 ){ + Complex com1 = this.toRectangular(); + Complex com2 = ph1.toRectangular(); + Complex com3 = com1.plus(com2); + Phasor ph2 = Phasor.toPhasor(com3); + this.magnitude = ph2.magnitude; + this.phaseInDeg = ph2.phaseInDeg; + this.phaseInRad = ph2.phaseInRad; + } + + // Add complex number to this Phasor and replace this with the sum + public void plusEquals(Complex com1 ){ + Complex com2 = this.toRectangular(); + Complex com3 = com1.plus(com2); + Phasor ph2 = Phasor.toPhasor(com3); + this.magnitude += ph2.magnitude; + this.phaseInDeg += ph2.phaseInDeg; + this.phaseInRad += ph2.phaseInRad; + } + + // SUBTRACTION + + // Subtract a Phasor from this Phasor + // this Phasor remains unaltered + public Phasor minus(Phasor ph){ + Complex com1 = this.toRectangular(); + Complex com2 = ph.toRectangular(); + Complex com3 = com1.minus(com2); + return Phasor.toPhasor(com3); + } + + // Subtract a complex number from this Phasor + // this Phasor remains unaltered + public Phasor minus(Complex com1){ + Phasor ph = new Phasor(); + Complex com2 = this.toRectangular(); + Complex com3 = com1.minus(com2); + return Phasor.toPhasor(com3); + } + + // Subtract a Phasor from this Phasor and replace this with the difference + public void minusEquals(Phasor ph1 ){ + Complex com1 = this.toRectangular(); + Complex com2 = ph1.toRectangular(); + Complex com3 = com1.plus(com2); + Phasor ph2 = Phasor.toPhasor(com3); + this.magnitude = ph2.magnitude; + this.phaseInDeg = ph2.phaseInDeg; + this.phaseInRad = ph2.phaseInRad; + } + + // Subtract a complex number from this Phasor and replace this with the difference + public void minusEquals(Complex com1 ){ + Complex com2 = this.toRectangular(); + Complex com3 = com1.plus(com2); + Phasor ph2 = Phasor.toPhasor(com3); + this.magnitude = ph2.magnitude; + this.phaseInDeg = ph2.phaseInDeg; + this.phaseInRad = ph2.phaseInRad; + } + + // MULTIPLICATION + + // Multiplies a Phasor by this Phasor + // this Phasor remains unaltered + public Phasor times(Phasor ph1){ + Phasor ph2 = new Phasor(); + double mag = this.magnitude*ph1.magnitude; + double pha = this.phaseInDeg + ph1.phaseInDeg; + ph2.reset(mag, pha); + return ph2; + } + + // Multiplies this Phasor by a Complex number + // this Phasor remains unaltered + public Phasor times(Complex com1){ + Phasor ph1 = Phasor.toPhasor(com1); + Phasor ph2 = new Phasor(); + double mag = this.magnitude*ph1.magnitude; + double pha = this.phaseInDeg + ph1.phaseInDeg; + ph2.reset(mag, pha); + return ph2; + } + + // Multiplies this Phasor by a double + // this Phasor remains unaltered + public Phasor times(double constant){ + Phasor ph2 = new Phasor(); + double mag = this.magnitude*constant; + double pha = this.phaseInDeg; + ph2.reset(mag, pha); + return ph2; + } + + // Multiplies this Phasor by an int + // this Phasor remains unaltered + public Phasor times(int constant){ + Phasor ph2 = new Phasor(); + double mag = this.magnitude*constant; + double pha = this.phaseInDeg; + ph2.reset(mag, pha); + return ph2; + } + + // Multiplies this Phasor by exp(omega.time) + // this Phasor remains unaltered + public Phasor timesExpOmegaTime(double omega, double time){ + if(Fmath.isNaN(Phasor.omega)){ + Phasor.omega = omega; + Phasor.frequency = Phasor.omega/(2.0D*Math.PI); + } + else{ + throw new IllegalArgumentException("You have already entered a value for the radial frequency, omega, " + Phasor.omega + ", that differs from the one you are now attempting to enter, " + omega); + } + Phasor ph2 = new Phasor(); + ph2.reset(this.magnitude, this.phaseInDeg + Math.toDegrees(omega*time)); + return ph2; + } + + // Multiplies this Phasor by exp(2.pi.frequency.time) + // this Phasor remains unaltered + public Phasor timesExpTwoPiFreqTime(double frequency, double time){ + if(Fmath.isNaN(Phasor.frequency)){ + Phasor.frequency = frequency; + Phasor.omega = Phasor.frequency*2.0D*Math.PI; + } + else{ + throw new IllegalArgumentException("You have already entered a value for the frequency, " + Phasor.frequency + ", that differs from the one you are now attempting to enter, " + frequency); + } + Phasor ph2 = new Phasor(); + ph2.reset(this.magnitude, this.phaseInDeg + Math.toDegrees(2.0D*Math.PI*frequency*time)); + return ph2; + } + + // Multiply a Phasor by this Phasor and replace this with the product + public void timesEquals(Phasor ph1 ){ + this.magnitude *= ph1.magnitude; + this.phaseInDeg += ph1.phaseInDeg; + this.phaseInRad += ph1.phaseInRad; + } + + // Multiply a complex number by this Phasor and replace this with the product + public void timesEquals(Complex com1 ){ + Phasor ph1 = Phasor.toPhasor(com1); + this.magnitude *= ph1.magnitude; + this.phaseInDeg += ph1.phaseInDeg; + this.phaseInRad += ph1.phaseInRad; + } + + // Multiply a double by this Phasor and replace this with the product + public void timesEquals(double constant ){ + this.magnitude *= constant; + } + + // Multiply an int by this Phasor and replace this with the product + public void timesEquals(int constant ){ + this.magnitude *= (double)constant; + } + + // Multiply exp(omega.time) by this Phasor and replace this with the product + public void timesEqualsOmegaTime(double omega, double time ){ + if(Fmath.isNaN(Phasor.omega)){ + Phasor.omega = omega; + Phasor.frequency = Phasor.omega/(2.0D*Math.PI); + } + else{ + throw new IllegalArgumentException("You have already entered a value for radial frequency, omega, " + Phasor.omega + ", that differs from the one you are now attempting to enter, " + omega); + } + this.phaseInRad += omega*time; + this.phaseInDeg = Math.toDegrees(this.phaseInRad); + } + + // Multiply exp(2.pi.frequency.time) by this Phasor and replace this with the product + public void timesEqualsTwoPiFreqTime(double frequency, double time ){ + if(Fmath.isNaN(Phasor.frequency)){ + Phasor.frequency = frequency; + Phasor.omega = Phasor.frequency*2.0D*Math.PI; + } + else{ + throw new IllegalArgumentException("You have already entered a value for the frequency, " + Phasor.frequency + ", that differs from the one you are now attempting to enter, " + frequency); + } + this.phaseInRad += 2.0D*Math.PI*frequency*time; + this.phaseInDeg = Math.toDegrees(this.phaseInRad); + } + + // DIVISION + + // Divides this Phasor by a Phasor + // this Phasor remains unaltered + public Phasor over(Phasor ph1){ + Phasor ph2 = new Phasor(); + double mag = this.magnitude/ph1.magnitude; + double pha = this.phaseInDeg - ph1.phaseInDeg; + ph2.reset(mag, pha); + return ph2; + } + + // Divides this Phasor by a Complex number + // this Phasor remains unaltered + public Phasor over(Complex com1){ + Phasor ph1 = Phasor.toPhasor(com1); + Phasor ph2 = new Phasor(); + double mag = this.magnitude/ph1.magnitude; + double pha = this.phaseInDeg - ph1.phaseInDeg; + ph2.reset(mag, pha); + return ph2; + } + + // Divides this Phasor by a double + // this Phasor remains unaltered + public Phasor over(double constant){ + Phasor ph2 = new Phasor(); + double mag = this.magnitude/constant; + double pha = this.phaseInDeg; + ph2.reset(mag, pha); + return ph2; + } + + // Divides this Phasor by an int + // this Phasor remains unaltered + public Phasor over(int constant){ + Phasor ph2 = new Phasor(); + double mag = this.magnitude/constant; + double pha = this.phaseInDeg; + ph2.reset(mag, pha); + return ph2; + } + + // Divide this Phasor by a Phasor and replace this with the quotient + public void overEquals(Phasor ph1 ){ + this.magnitude /= ph1.magnitude; + this.phaseInDeg -= ph1.phaseInDeg; + this.phaseInRad -= ph1.phaseInRad; + } + + // Divide this Phasor by a complex number and replace this with the quotient + public void overEquals(Complex com1 ){ + Phasor ph1 = Phasor.toPhasor(com1); + this.magnitude /= ph1.magnitude; + this.phaseInDeg -= ph1.phaseInDeg; + this.phaseInRad -= ph1.phaseInRad; + } + + // Divide this Phasor by a double and replace this with the quotient + public void overEquals(double constant ){ + this.magnitude /= constant; + } + + // Divide this Phasor by an int and replace this with the quotient + public void overEquals(int constant ){ + this.magnitude /= (double)constant; + } + + // FURTHER MATHEMATICAL FUNCTIONS + + // Return the absolute value of the magnitude + // changes the sign of the magnitude + public double abs(){ + return Math.abs(this.magnitude); + } + + // Return the phase in radians + // identical method to getPhaseInRadians() + public double argInRadians(){ + return this.phaseInRad; + } + + // Return the phase in degrees + // identical method to getPhaseInDegrees() + public double argInDegrees(){ + return this.phaseInDeg; + } + + // negates a Phasor + // changes the sign of the magnitude + public Phasor negate(){ + Phasor ph = new Phasor(); + ph.reset(-this.magnitude, this.phaseInDeg); + return ph; + } + + // returns the complex conjugate of the Phasor + public Phasor conjugate(){ + Phasor ph = new Phasor(); + ph.reset(this.magnitude, -this.phaseInDeg); + return ph; + } + + // inverts the Phasor + public Phasor inverse(){ + Phasor ph = new Phasor(); + ph.reset(1.0D/this.magnitude, -this.phaseInDeg); + return ph; + } + + // Roots + // square root of a Phasor + public static Phasor sqrt(Phasor ph1){ + Phasor ph2 = new Phasor(); + ph2.reset(Math.sqrt(ph1.magnitude), ph1.phaseInDeg/2.0D); + return ph2; + } + + // nth root of a Phasor + public static Phasor nthRoot(Phasor ph1, int n){ + if(n<=0)throw new IllegalArgumentException("The root, " + n + ", must be greater than zero"); + Phasor ph2 = new Phasor(); + ph2.reset(Math.pow(ph1.magnitude, 1.0/n), ph1.phaseInDeg/n); + return ph2; + } + + // Powers + // square of a Phasor + public static Phasor square(Phasor ph1){ + Phasor ph2 = new Phasor(); + ph2.reset(Fmath.square(ph1.magnitude), 2.0D*ph1.phaseInDeg); + return ph2; + } + + // nth power of a Phasor - int n + public static Phasor pow(Phasor ph1, int n){ + Phasor ph2 = new Phasor(); + ph2.reset(Math.pow(ph1.magnitude, n), n*ph1.phaseInDeg); + return ph2; + } + + // nth power of a Phasor - double n + public static Phasor pow(Phasor ph1, double n){ + Phasor ph2 = new Phasor(); + ph2.reset(Math.pow(ph1.magnitude, n), n*ph1.phaseInDeg); + return ph2; + } + + // nth power of a Phasor - Complex n + public static Phasor pow(Phasor ph1, Complex n){ + Complex com1 = ph1.toRectangular(); + Complex com2 = Complex.pow(com1, n); + Phasor ph2 = Phasor.toPhasor(com2); + return ph2; + } + + // nth power of a Phasor - Phasor n + public static Phasor pow(Phasor ph1, Phasor n){ + Complex com1 = ph1.toRectangular(); + Complex comn = n.toRectangular(); + Complex com2 = Complex.pow(com1, comn); + Phasor ph2 = Phasor.toPhasor(com2); + return ph2; + } + + + // Exponential of a Phasor + public static Phasor exp(Phasor ph1){ + Complex com = ph1.toRectangular(); + com = Complex.exp(com); + Phasor ph2 = Phasor.toPhasor(com); + return ph2; + } + + // Natural log of a Phasor + public static Phasor log(Phasor ph1){ + Complex com = new Complex(Math.log(ph1.magnitude), ph1.phaseInDeg); + Phasor ph2 = Phasor.toPhasor(com);; + return ph2; + } + + // Trigonometric Functions + // sine + public Phasor sin(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Math.sin(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.sin(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // cosine + public Phasor cos(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Math.cos(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.cos(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // tangent + public Phasor tan(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Math.tan(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.tan(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // cotangent + public Phasor cot(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.cot(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.cot(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // secant + public Phasor sec(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.sec(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.sec(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // cosecant + public Phasor csc(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.csc(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.csc(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // exssecant + public Phasor exsec(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.exsec(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.exsec(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // versine + public Phasor vers(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.vers(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.vers(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // coversine + public Phasor covers(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.covers(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.covers(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // haversine + public Phasor hav(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.hav(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.hav(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // hyperbolic sine + public Phasor sinh(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.sinh(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.sinh(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // hyperbolic cosine + public Phasor cosh(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.cosh(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.cosh(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // hyperbolic secant + public Phasor sech(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.sech(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.sech(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // hyperbolic cosecant + public Phasor csch(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.csch(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.csch(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + // Inverse Trigonometric Functions + // inverse sine + public Phasor asin(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Math.asin(ph1.getMagnitude()), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.asin(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // inverse cosine + public Phasor acos(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Math.acos(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.acos(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // inverse tangent + public Phasor atan(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Math.atan(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.atan(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // inverse cotangent + public Phasor acot(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.acot(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.acot(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // inverse secant + public Phasor asec(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.asec(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.asec(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // inverse cosecant + public Phasor acsc(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.acsc(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.acsc(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // inverse exssecant + public Phasor aexsec(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.aexsec(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.aexsec(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // inverse versine + public Phasor avers(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.avers(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.avers(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // inverse coversine + public Phasor acovers(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.acovers(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.acovers(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // inverse haversine + public Phasor ahav(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.ahav(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.ahav(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // inverse hyperbolic sine + public Phasor asinh(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.asinh(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.asinh(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // inverse hyperbolic cosine + public Phasor acosh(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.acosh(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.acosh(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // inverse hyperbolic secant + public Phasor asech(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.asech(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.asech(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + // inverse hyperbolic cosecant + public Phasor acsch(Phasor ph1){ + Phasor ph2 = new Phasor(); + if(ph1.phaseInDeg==0.0){ + ph2.reset(Fmath.acsch(ph1.magnitude), 0.0D); + } + else{ + Complex com = ph1.toRectangular(); + com = Complex.acsch(com); + ph2 = Phasor.toPhasor(com); + } + + return ph2; + } + + + // LOGICAL FUNCTIONS + // Returns true if the Phasor has a zero phase, i.e. is a real number + public boolean isReal(){ + boolean test = false; + if(Math.abs(this.phaseInDeg)==0.0D)test = true; + return test; + } + + // Returns true if the Phasor has a zero magnitude + // or a phase equal to minus infinity + public boolean isZero(){ + boolean test = false; + if(Math.abs(this.magnitude)==0.0D || this.phaseInDeg==Double.NEGATIVE_INFINITY)test = true; + return test; + } + + // Returns true if either the magnitude or the phase of the Phasor + // is equal to plus infinity + public boolean isPlusInfinity(){ + boolean test = false; + if(this.magnitude==Double.POSITIVE_INFINITY || this.phaseInDeg==Double.POSITIVE_INFINITY)test = true; + return test; + } + + + // Returns true if the magnitude of the Phasor + // is equal to minus infinity + public boolean isMinusInfinity(){ + boolean test = false; + if(this.magnitude==Double.NEGATIVE_INFINITY)test = true; + return test; + } + + // Returns true if the Phasor is NaN (Not a Number) + // i.e. is the result of an uninterpretable mathematical operation + public boolean isNaN(){ + boolean test = false; + if(this.magnitude!=this.magnitude || this.phaseInDeg!=this.phaseInDeg)test = true; + return test; + } + + // Returns true if two Phasor are identical + // Follows the Sun Java convention of treating all NaNs as equal + // i.e. does not satisfies the IEEE 754 specification + // but does let hashtables operate properly + public boolean equals(Phasor a){ + boolean test = false; + if(this.isNaN() && a.isNaN()){ + test=true; + } + else{ + if(this.magnitude == a.magnitude && this.phaseInDeg == a.phaseInDeg)test = true; + } + return test; + } + + + + // returns true if the differences between the magnitudes and phases of two Phasors + // are less than fract times the larger magnitude or phase + public boolean equalsWithinLimits(Phasor a, double fract){ + + boolean test = false; + + double mt = this.magnitude; + double ma = a.magnitude; + double pt = this.phaseInDeg; + double pa = a.phaseInDeg; + double mdn = 0.0D; + double pdn = 0.0D; + double mtest = 0.0D; + double ptest = 0.0D; + + if(mt==0.0D && pt==0.0D && ma==0.0D && pa==0.0D)test=true; + if(!test){ + mdn=Math.abs(mt); + if(Math.abs(ma)>mdn)mdn=Math.abs(ma); + if(mdn==0.0D){ + mtest=0.0; + } + else{ + mtest=Math.abs(ma-mt)/mdn; + } + pdn=Math.abs(pt); + if(Math.abs(pa)>pdn)pdn=Math.abs(pa); + if(pdn==0.0D){ + ptest=0.0; + } + else{ + ptest=Math.abs(pa-pt)/pdn; + } + if(mtest<fract && ptest<fract)test=true; + } + + return test; + } + + // SOME USEFUL NUMBERS + // returns the number zero (0) as a Phasor + // zero magnituded and zero phase + public static Phasor zero(){ + Phasor ph = new Phasor(); + ph.magnitude = 0.0D; + ph.phaseInDeg = 0.0D; + ph.phaseInRad = 0.0D; + ph.rectangular.polar(ph.magnitude, ph.phaseInRad); + return ph; + } + + // returns the number one (+1) as a Phasor + // magnitude = 1, phase = zero + public static Phasor plusOne(){ + Phasor ph = new Phasor(); + ph.magnitude = 1.0D; + ph.phaseInDeg = 0.0D; + ph.phaseInRad = 0.0D; + ph.rectangular.polar(ph.magnitude, ph.phaseInRad); + return ph; + } + + // returns the number minus one (-1) as a Phasor + // magnitude = -1, phase = zero + public static Phasor minusOne(){ + Phasor ph = new Phasor(); + ph.magnitude = -1.0D; + ph.phaseInDeg = 0.0D; + ph.phaseInRad = 0.0D; + ph.rectangular.polar(ph.magnitude, ph.phaseInRad); + return ph; + } + + // returns the a phasor of given magnitude with zero phase + // magnitude = -1, phase = zero + public static Phasor magnitudeZeroPhase(double mag){ + Phasor ph = new Phasor(); + ph.magnitude = mag; + ph.phaseInDeg = 0.0D; + ph.phaseInRad = 0.0D; + ph.rectangular.polar(ph.magnitude, ph.phaseInRad); + return ph; + } + + // infinity + // magnitude = plus infinity, phase = 0 + public static Phasor plusInfinity(){ + Phasor ph = new Phasor(); + ph.magnitude = Double.POSITIVE_INFINITY; + ph.phaseInDeg = 0.0D; + ph.phaseInRad = 0.0D; + ph.rectangular = new Complex(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + return ph; + } + + // -infinity + // magnitude = minus infinity, phase = 0 + public static Phasor minusInfinity(){ + Phasor ph = new Phasor(); + ph.magnitude = Double.NEGATIVE_INFINITY; + ph.phaseInDeg = 0.0D; + ph.phaseInRad = 0.0D; + ph.rectangular = new Complex(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY); + return ph; + } + + // Resistance as a phasor + public static Phasor resistancePhasor(double resistance){ + Phasor ph = new Phasor(resistance); + return ph; + } + + // inductance as a phasor + public static Phasor inductancePhasor(double inductance, double frequency){ + if(Fmath.isNaN(Phasor.frequency)){ + Phasor.frequency = frequency; + Phasor.omega = Phasor.frequency*2.0D*Math.PI; + } + else{ + throw new IllegalArgumentException("You have already entered a value for the frequency, " + Phasor.frequency + ", that differs from the one you are now attempting to enter, " + frequency); + } + Complex com = Impedance.inductanceImpedance(inductance, Phasor.omega); + Phasor ph = new Phasor(); + return ph.toPhasor(com); + } + + // capacitance as a phasor + public static Phasor capacitancePhasor(double capacitance, double frequency){ + if(Fmath.isNaN(Phasor.frequency)){ + Phasor.frequency = frequency; + Phasor.omega = Phasor.frequency*2.0D*Math.PI; + } + else{ + throw new IllegalArgumentException("You have already entered a value for the frequency, " + Phasor.frequency + ", that differs from the one you are now attempting to enter, " + frequency); + } + Complex com = Impedance.capacitanceImpedance(capacitance, Phasor.omega); + Phasor ph = new Phasor(); + return ph.toPhasor(com); + } + + // infinite warburg impedance as a phasor + public static Phasor infiniteWarburgPhasor(double sigma, double frequency){ + if(Fmath.isNaN(Phasor.frequency)){ + Phasor.frequency = frequency; + Phasor.omega = Phasor.frequency*2.0D*Math.PI; + } + else{ + throw new IllegalArgumentException("You have already entered a value for the frequency, " + Phasor.frequency + ", that differs from the one you are now attempting to enter, " + frequency); + } + Complex com = Impedance.infiniteWarburgImpedance(sigma, Phasor.omega); + Phasor ph = new Phasor(); + return ph.toPhasor(com); + } + + // finite warburg impedance as a phasor + public static Phasor finiteWarburgPhasor(double sigma, double delta, double frequency){ + if(Fmath.isNaN(Phasor.frequency)){ + Phasor.frequency = frequency; + Phasor.omega = Phasor.frequency*2.0D*Math.PI; + } + else{ + throw new IllegalArgumentException("You have already entered a value for the frequency, " + Phasor.frequency + ", that differs from the one you are now attempting to enter, " + frequency); + } + Complex com = Impedance.finiteWarburgImpedance(sigma, delta, Phasor.omega); + Phasor ph = new Phasor(); + return ph.toPhasor(com); + } + + // constant phase elelemnt a phasor + public static Phasor constantPhaseElementPhasor(double sigma, double alpha, double frequency){ + if(Fmath.isNaN(Phasor.frequency)){ + Phasor.frequency = frequency; + Phasor.omega = Phasor.frequency*2.0D*Math.PI; + } + else{ + throw new IllegalArgumentException("You have already entered a value for the frequency, " + Phasor.frequency + ", that differs from the one you are now attempting to enter, " + frequency); + } + Complex com = Impedance.constantPhaseElementImpedance(sigma, alpha, Phasor.omega); + Phasor ph = new Phasor(); + return ph.toPhasor(com); + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/circuits/PhasorMatrix.java b/src/main/java/flanagan/circuits/PhasorMatrix.java new file mode 100755 index 0000000000000000000000000000000000000000..1716eb639bfb1261fe6dc39c8e0ed92b84661294 --- /dev/null +++ b/src/main/java/flanagan/circuits/PhasorMatrix.java @@ -0,0 +1,1293 @@ +/* +* Class PhasorMatrix +* +* Defines a complex matrix and includes the methods +* needed for standard matrix manipulations, e.g. multiplation, +* and related procedures, e.g. solution of complex linear +* simultaneous equations +* +* See class ComplexMatrix for rectangular complex matrix manipulations +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: July 2007 +* AMENDED: 19 April 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/PhasorMatrix.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2007 - 2008 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.circuits; + +import flanagan.math.Fmath; +import flanagan.math.Matrix; +import flanagan.complex.Complex; +import flanagan.complex.ComplexMatrix; + +public class PhasorMatrix{ + + private int nrow = 0; // number of rows + private int ncol = 0; // number of columns + private Phasor matrix[][] = null; // 2-D Phasor Matrix + private int index[] = null; // row permutation index + private double dswap = 1.0D; // row swap index + private static final double TINY = 1.0e-30; + +/*********************************************************/ + + // CONSTRUCTORS + // Construct a nrow x ncol matrix of complex variables all equal to zero + public PhasorMatrix(int nrow, int ncol){ + this.nrow = nrow; + this.ncol = ncol; + this.matrix = Phasor.twoDarray(nrow, ncol); + this.index = new int[nrow]; + for(int i=0;i<nrow;i++)this.index[i]=i; + this.dswap=1.0; + } + + // Construct a nrow x ncol matrix of complex variables all equal to the complex number const + public PhasorMatrix(int nrow, int ncol, Phasor constant){ + this.nrow = nrow; + this.ncol = ncol; + this.matrix = Phasor.twoDarray(nrow, ncol, constant); + this.index = new int[nrow]; + for(int i=0;i<nrow;i++)this.index[i]=i; + this.dswap=1.0; + } + + // Construct matrix with a reference to an existing nrow x ncol 2-D array of complex variables + public PhasorMatrix(Phasor[][] twoD){ + this.nrow = twoD.length; + this.ncol = twoD[0].length; + for(int i=0; i<nrow; i++){ + if(twoD[i].length!=ncol)throw new IllegalArgumentException("All rows must have the same length"); + } + this.matrix = twoD; + this.index = new int[nrow]; + for(int i=0;i<nrow;i++)this.index[i]=i; + this.dswap=1.0; + } + + // Construct matrix with a reference to the 2D matrix and permutation index of an existing PhasorMatrix bb. + public PhasorMatrix(PhasorMatrix bb){ + this.nrow = bb.nrow; + this.ncol = bb.ncol; + this.matrix = bb.matrix; + this.index = bb.index; + this.dswap = bb.dswap; + } + + + // SET VALUES + // Set the matrix with a copy of an existing nrow x ncol 2-D matrix of Phasor variables + public void setTwoDarray(Phasor[][] aarray){ + if(this.nrow != aarray.length)throw new IllegalArgumentException("row length of this PhasorMatrix differs from that of the 2D array argument"); + if(this.ncol != aarray[0].length)throw new IllegalArgumentException("column length of this PhasorMatrix differs from that of the 2D array argument"); + for(int i=0; i<nrow; i++){ + if(aarray[i].length!=ncol)throw new IllegalArgumentException("All rows must have the same length"); + for(int j=0; j<ncol; j++){ + this.matrix[i][j]=Phasor.copy(aarray[i][j]); + } + } + } + + // Set an individual array element + // i = row index + // j = column index + // aa = value of the element + public void setElement(int i, int j, Phasor aa){ + this.matrix[i][j]=Phasor.copy(aa); + } + + // Set an individual array element + // i = row index + // j = column index + // aa = magnitude of the element + // bb = phase of the element + public void setElement(int i, int j, double aa, double bb){ + this.matrix[i][j].reset(aa, bb); + } + + // Set a sub-matrix starting with row index i, column index j + + public void setSubMatrix(int i, int j, Phasor[][] subMatrix){ + int k = subMatrix.length; + int l = subMatrix[0].length; + if(i>k)throw new IllegalArgumentException("row indices inverted"); + if(j>l)throw new IllegalArgumentException("column indices inverted"); + int n=k-i+1, m=l-j+1; + for(int p=0; p<n; p++){ + for(int q=0; q<m; q++){ + this.matrix[i+p][j+q] = Phasor.copy(subMatrix[p][q]); + } + } + } + + // Set a sub-matrix starting with row index i, column index j + // and ending with row index k, column index l + public void setSubMatrix(int i, int j, int k, int l, Phasor[][] subMatrix){ + if(i>k)throw new IllegalArgumentException("row indices inverted"); + if(j>l)throw new IllegalArgumentException("column indices inverted"); + int n=k-i+1, m=l-j+1; + for(int p=0; p<n; p++){ + for(int q=0; q<m; q++){ + this.matrix[i+p][j+q] = Phasor.copy(subMatrix[p][q]); + } + } + } + + + // Set a sub-matrix + // row = array of row indices + // col = array of column indices + public void setSubMatrix(int[] row, int[] col, Phasor[][] subMatrix){ + int n=row.length; + int m=col.length; + for(int p=0; p<n; p++){ + for(int q=0; q<m; q++){ + this.matrix[row[p]][col[q]] = Phasor.copy(subMatrix[p][q]); + } + } + } + + // SPECIAL MATRICES + // Construct a Phasor identity matrix + public static PhasorMatrix identityMatrix(int nrow){ + PhasorMatrix u = new PhasorMatrix(nrow, nrow); + for(int i=0; i<nrow; i++){ + u.matrix[i][i]=Phasor.plusOne(); + } + return u; + } + + // Construct a Phasor scalar matrix + public static PhasorMatrix scalarMatrix(int nrow, Phasor diagconst){ + PhasorMatrix u = new PhasorMatrix(nrow, nrow); + Phasor[][] uarray = u.getArrayReference(); + for(int i=0; i<nrow; i++){ + for(int j=i; j<nrow; j++){ + if(i==j){ + uarray[i][j]=Phasor.copy(diagconst); + } + } + } + return u; + } + + // Construct a Phasor diagonal matrix + public static PhasorMatrix diagonalMatrix(int nrow, Phasor[] diag){ + if(diag.length!=nrow)throw new IllegalArgumentException("matrix dimension differs from diagonal array length"); + PhasorMatrix u = new PhasorMatrix(nrow, nrow); + Phasor[][] uarray = u.getArrayReference(); + for(int i=0; i<nrow; i++){ + for(int j=i; j<nrow; j++){ + if(i==j){ + uarray[i][j]=Phasor.copy(diag[i]); + } + } + } + return u; + } + + // COLUMN MATRICES + // Converts a 1-D array of Phasor to a column matrix + public static PhasorMatrix columnMatrix(Phasor[] darray){ + int nr = darray.length; + PhasorMatrix pp = new PhasorMatrix(nr, 1); + for(int i=0; i<nr; i++)pp.matrix[i][0] = darray[i]; + return pp; + } + + // ROW MATRICES + // Converts a 1-D array of Phasor to a row matrix + public static PhasorMatrix rowMatrix(Phasor[] darray){ + int nc = darray.length; + PhasorMatrix pp = new PhasorMatrix(1, nc); + for(int i=0; i<nc; i++)pp.matrix[0][i] = darray[i]; + return pp; + } + + + // GET VALUES + // Return the number of rows + public int getNrow(){ + return this.nrow; + } + + // Return the number of columns + public int getNcol(){ + return this.ncol; + } + + // Return a reference to the internal 2-D array + public Phasor[][] getArrayReference(){ + return this.matrix; + } + + // Return a reference to the internal 2-D array + public Phasor[][] getArray(){ + return this.matrix; + } + + // Return a reference to the internal 2-D array + // included for backward compatibility with earlier incorrect documentation + public Phasor[][] getArrayPointer(){ + return this.matrix; + } + + // Return a copy of the internal 2-D array + public Phasor[][] getArrayCopy(){ + Phasor[][] c = new Phasor[this.nrow][this.ncol]; + for(int i=0; i<nrow; i++){ + for(int j=0; j<ncol; j++){ + c[i][j]=Phasor.copy(matrix[i][j]); + } + } + return c; + } + + // Return a single element of the internal 2-D array + public Phasor getElementReference(int i, int j){ + return this.matrix[i][j]; + } + + // Return a reference to a single element of the internal 2-D array + // included for backward compatibility with earlier incorrect documentation + public Phasor getElementPointer(int i, int j){ + return this.matrix[i][j]; + } + + // Return a copy of a single element of the internal 2-D array + public Phasor getElementCopy(int i, int j){ + return Phasor.copy(this.matrix[i][j]); + } + + // Return a sub-matrix starting with row index i, column index j + // and ending with column index k, row index l + public PhasorMatrix getSubMatrix(int i, int j, int k, int l){ + if(i>k)throw new IllegalArgumentException("row indices inverted"); + if(j>l)throw new IllegalArgumentException("column indices inverted"); + int n=k-i+1, m=l-j+1; + PhasorMatrix subMatrix = new PhasorMatrix(n, m); + Phasor[][] sarray = subMatrix.getArrayReference(); + for(int p=0; p<n; p++){ + for(int q=0; q<m; q++){ + sarray[p][q]=Phasor.copy(this.matrix[i+p][j+q]); + } + } + return subMatrix; + } + + // Return a sub-matrix + // row = array of row indices + // col = array of column indices + public PhasorMatrix getSubMatrix(int[] row, int[] col){ + int n = row.length; + int m = col.length; + PhasorMatrix subMatrix = new PhasorMatrix(n, m); + Phasor[][] sarray = subMatrix.getArrayReference(); + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + sarray[i][j]=Phasor.copy(this.matrix[row[i]][col[j]]); + } + } + return subMatrix; + } + + // Return a reference to the permutation index array + public int[] getIndexReference(){ + return this.index; + } + + // Return a reference to the permutation index array + public int[] getIndexPointer(){ + return this.index; + } + + // Return a copy of the permutation index array + public int[] getIndexCopy(){ + int[] indcopy = new int[this.nrow]; + for(int i=0; i<this.nrow; i++){ + indcopy[i]=this.index[i]; + } + return indcopy; + } + + // Return the row swap index + public double getSwap(){ + return this.dswap; + } + + // COPY + // Copy a PhasorMatrix [static method] + public static PhasorMatrix copy(PhasorMatrix a){ + if(a==null){ + return null; + } + else{ + int nr = a.getNrow(); + int nc = a.getNcol(); + Phasor[][] aarray = a.getArrayReference(); + PhasorMatrix b = new PhasorMatrix(nr,nc); + b.nrow = nr; + b.ncol = nc; + Phasor[][] barray = b.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + barray[i][j]=Phasor.copy(aarray[i][j]); + } + } + for(int i=0; i<nr; i++)b.index[i] = a.index[i]; + return b; + } + } + + // Copy a PhasorMatrix [instance method] + public PhasorMatrix copy(){ + if(this==null){ + return null; + } + else{ + int nr = this.nrow; + int nc = this.ncol; + PhasorMatrix b = new PhasorMatrix(nr,nc); + Phasor[][] barray = b.getArrayReference(); + b.nrow = nr; + b.ncol = nc; + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + barray[i][j]=Phasor.copy(this.matrix[i][j]); + } + } + for(int i=0; i<nr; i++)b.index[i] = this.index[i]; + return b; + } + } + + // Clone a PhasorMatrix + public Object clone(){ + if(this==null){ + return null; + } + else{ + int nr = this.nrow; + int nc = this.ncol; + PhasorMatrix b = new PhasorMatrix(nr,nc); + Phasor[][] barray = b.getArrayReference(); + b.nrow = nr; + b.ncol = nc; + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + barray[i][j]=Phasor.copy(this.matrix[i][j]); + } + } + for(int i=0; i<nr; i++)b.index[i] = this.index[i]; + return (Object) b; + } + } + + // CONVERSIONS + // Converts a 1-D array of Phasors to a row phasor matrix + public static PhasorMatrix toPhasorRowMatrix(Phasor[] parray){ + int nc = parray.length; + PhasorMatrix pp = new PhasorMatrix(1, nc); + for(int i=0; i<nc; i++)pp.matrix[0][i] = parray[i].copy(); + return pp; + } + + // Converts a 1-D array of Complex to a row phasor matrix + public static PhasorMatrix toPhasorRowMatrix(Complex[] carray){ + int nc = carray.length; + PhasorMatrix pp = new PhasorMatrix(1, nc); + for(int i=0; i<nc; i++)pp.matrix[0][i] = Phasor.toPhasor(carray[i]).copy(); + return pp; + } + + // Converts a 1-D array of doubles to a row phasor matrix + public static PhasorMatrix toPhasorRowMatrix(double[] darray){ + int nc = darray.length; + PhasorMatrix pp = new PhasorMatrix(1, nc); + for(int i=0; i<nc; i++)pp.matrix[0][i] = new Phasor(darray[i], 0.0D); + return pp; + } + + // Converts a 1-D array of Phasors to a column phasor matrix + public static PhasorMatrix toPhasorColumnMatrix(Phasor[] parray){ + int nr = parray.length; + PhasorMatrix pp = new PhasorMatrix(nr, 1); + for(int i=0; i<nr; i++)pp.matrix[i][0] = parray[i].copy(); + return pp; + } + + // Converts a 1-D array of Complex to a column phasor matrix + public static PhasorMatrix toPhasorColumnMatrix(Complex[] carray){ + int nr = carray.length; + PhasorMatrix pp = new PhasorMatrix(nr, 1); + for(int i=0; i<nr; i++)pp.matrix[i][0] = Phasor.toPhasor(carray[i]).copy(); + return pp; + } + + // Converts a 1-D array of doubles to a column phasor matrix + public static PhasorMatrix toPhasorColumnMatrix(double[] darray){ + int nr = darray.length; + PhasorMatrix pp = new PhasorMatrix(nr, 1); + for(int i=0; i<nr; i++)pp.matrix[i][0] = new Phasor(darray[i], 0.0D); + return pp; + } + + // Converts a complex matrix (ComplexMatrix) to a phasor matrix (PhasorMatix) + public static PhasorMatrix toPhasorMatrix(ComplexMatrix cc){ + PhasorMatrix pp = new PhasorMatrix(cc.getNrow(), cc.getNcol() ); + pp.index = cc.getIndexCopy(); + pp.dswap = cc.getSwap(); + for(int i=0; i<pp.nrow; i++){ + for(int j=0; j<pp.ncol; i++){ + pp.matrix[i][j] = Phasor.toPhasor(cc.getElementCopy(i,j)); + } + } + return pp; + } + + // Converts a 2D complex array to a phasor matrix (PhasorMatix) + public static PhasorMatrix toPhasorMatrix(Complex[][] carray){ + ComplexMatrix cc = new ComplexMatrix(carray); + PhasorMatrix pp = new PhasorMatrix(cc.getNrow(), cc.getNcol() ); + for(int i=0; i<pp.nrow; i++){ + for(int j=0; j<pp.ncol; i++){ + pp.matrix[i][j] = Phasor.toPhasor(cc.getElementCopy(i,j)); + } + } + return pp; + } + + // Converts a matrix of doubles (Matrix) to a phasor matrix (PhasorMatix) + public static PhasorMatrix toPhasorMatrix(Matrix marray){ + int nr = marray.getNrow(); + int nc = marray.getNcol(); + + PhasorMatrix pp = new PhasorMatrix(nr, nc); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + pp.matrix[i][j].reset(marray.getElementCopy(i, j), 0.0D); + } + } + return pp; + } + + // Converts a 2D array of doubles to a phasor matrix (PhasorMatix) + public static PhasorMatrix toPhasorMatrix(double[][] darray){ + int nr = darray.length; + int nc = darray[0].length; + for(int i=1; i<nr; i++){ + if(darray[i].length!=nc)throw new IllegalArgumentException("All rows must have the same length"); + } + PhasorMatrix pp = new PhasorMatrix(nr, nc); + for(int i=0; i<pp.nrow; i++){ + for(int j=0; j<pp.ncol; j++){ + pp.matrix[i][j].reset(darray[i][j], 0.0D); + } + } + return pp; + } + + // Converts a phasor matrix (PhasorMatix) to a complex matrix (ComplexMatrix) - instance method + public ComplexMatrix toComplexMatrix(){ + int nr = this.getNrow(); + int nc = this.getNcol(); + ComplexMatrix cc = new ComplexMatrix(nr, nc); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; i++){ + cc.setElement(i, j, this.matrix[i][j].toRectangular()); + } + } + return cc; + } + + // Converts a phasor matrix (PhasorMatix) to a complex matrix (ComplexMatrix) - static method + public static ComplexMatrix toComplexMatrix(PhasorMatrix pp){ + int nr = pp.getNrow(); + int nc = pp.getNcol(); + ComplexMatrix cc = new ComplexMatrix(nr, nc); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; i++){ + cc.setElement(i, j, pp.matrix[i][j].toRectangular()); + } + } + return cc; + } + + + // ADDITION + // Add this matrix to matrix B. This matrix remains unaltered + public PhasorMatrix plus(PhasorMatrix bmat){ + if((this.nrow!=bmat.nrow)||(this.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=bmat.nrow; + int nc=bmat.ncol; + PhasorMatrix cmat = new PhasorMatrix(nr,nc); + Phasor[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j].plus(bmat.matrix[i][j]); + } + } + return cmat; + } + + // Add this matrix to a Phasor 2-D array. + public PhasorMatrix plus(Phasor[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if((this.nrow!=nr)||(this.ncol!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + PhasorMatrix cmat = new PhasorMatrix(nr,nc); + Phasor[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j].plus(bmat[i][j]); + } + } + return cmat; + } + + // Add this PhasorMatrix to a ComplexMatrix. + public PhasorMatrix plus(ComplexMatrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.plus(pmat); + } + + // Add this PhasorMatrix to a 2D array of Complex. + public PhasorMatrix plus(Complex[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.plus(pmat); + } + + // Add this PhasorMatrix to a Matrix. + public PhasorMatrix plus(Matrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.plus(pmat); + } + + // Add this PhasorMatrix to a 2D array of double. + public PhasorMatrix plus(double[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.plus(pmat); + } + + // Add a PhasorMatrix to this matrix [equivalence of +=] + public void plusEquals(PhasorMatrix bmat){ + if((this.nrow!=bmat.nrow)||(this.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=bmat.nrow; + int nc=bmat.ncol; + + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + this.matrix[i][j].plusEquals(bmat.matrix[i][j]); + } + } + } + + // Add a 2D array of Phasors to this matrix [equivalence of +=] + public void plusEquals(Phasor[][] bmat){ + PhasorMatrix pmat = new PhasorMatrix(bmat); + this.plusEquals(pmat); + } + + // Add a ComplexMatrix of complex to this matrix [equivalence of +=] + public void plusEquals(ComplexMatrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.plusEquals(pmat); + } + + // Add a 2D array of complex to this matrix [equivalence of +=] + public void plusEquals(Complex[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.plusEquals(pmat); + } + + // Add a Matrix to this PhasorMatrix [equivalence of +=] + public void plusEquals(Matrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.plusEquals(pmat); + } + + // Add a 2D array of doubles to this matrix [equivalence of +=] + public void plusEquals(double[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.plusEquals(pmat); + } + + // SUBTRACTION + // Subtract matrix B from this matrix. This matrix remains unaltered [instance method] + public PhasorMatrix minus(PhasorMatrix bmat){ + if((this.nrow!=bmat.nrow)||(this.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=this.nrow; + int nc=this.ncol; + PhasorMatrix cmat = new PhasorMatrix(nr,nc); + Phasor[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j].minus(bmat.matrix[i][j]); + } + } + return cmat; + } + + // Subtract Phasor 2-D array from this matrix. [instance method] + public PhasorMatrix minus(Phasor[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if((this.nrow!=nr)||(this.ncol!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + PhasorMatrix cmat = new PhasorMatrix(nr,nc); + Phasor[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j].minus(bmat[i][j]); + } + } + return cmat; + } + + // Subtract a ComplexMatrix from this PhasorMatrix + public PhasorMatrix minus(ComplexMatrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.minus(pmat); + } + + // Subtract a 2D array of Complex from this PhasorMatrix. + public PhasorMatrix minus(Complex[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.minus(pmat); + } + + // Subtract a Matrix from this PhasorMatrix. + public PhasorMatrix minus(Matrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.minus(pmat); + } + + // Subtract a 2D array of doubles from this PhasorMatrix. + public PhasorMatrix minus(double[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.minus(pmat); + } + + + // Subtract a PhasorMatrix from this matrix [equivalence of -=] + public void minusEquals(PhasorMatrix bmat){ + if((this.nrow!=bmat.nrow)||(this.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=bmat.nrow; + int nc=bmat.ncol; + + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + this.matrix[i][j].minusEquals(bmat.matrix[i][j]); + } + } + } + + // Subtract a 2D array of Phasors from this matrix [equivalence of -=] + public void minusEquals(Phasor[][] bmat){ + PhasorMatrix pmat = new PhasorMatrix(bmat); + this.minusEquals(pmat); + } + + // Subtract a ComplexMatrix from this matrix [equivalence of -=] + public void minusEquals(ComplexMatrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.minusEquals(pmat); + } + + // Subtract a 2D array of complex from this matrix [equivalence of -=] + public void minusEquals(Complex[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.minusEquals(pmat); + } + + // Subtract a Matrix from this phasorMatrix [equivalence of -=] + public void minusEquals(Matrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.minusEquals(pmat); + } + + // Subtract a 2D array of doubles from this matrix [equivalence of -=] + public void minusEquals(double[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.minusEquals(pmat); + } + + // MULTIPLICATION + // Multiply this Phasor matrix by a Phasor matrix. + // This matrix remains unaltered. + public PhasorMatrix times(PhasorMatrix bmat){ + if(this.ncol!=bmat.nrow)throw new IllegalArgumentException("Nonconformable matrices"); + + PhasorMatrix cmat = new PhasorMatrix(this.nrow, bmat.ncol); + Phasor [][] carray = cmat.getArrayReference(); + Phasor sum = new Phasor(); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<bmat.ncol; j++){ + sum=Phasor.zero(); + for(int k=0; k<this.ncol; k++){ + sum.plusEquals(this.matrix[i][k].times(bmat.matrix[k][j])); + } + carray[i][j]=Phasor.copy(sum); + } + } + return cmat; + } + + // Multiply this Phasor matrix by a Phasor 2-D array. + public PhasorMatrix times(Phasor[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if(this.ncol!=nr)throw new IllegalArgumentException("Nonconformable matrices"); + + PhasorMatrix cmat = new PhasorMatrix(this.nrow, nc); + Phasor [][] carray = cmat.getArrayReference(); + Phasor sum = new Phasor(); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<nc; j++){ + sum=Phasor.zero(); + for(int k=0; k<this.ncol; k++){ + sum.plusEquals(this.matrix[i][k].times(bmat[k][j])); + } + carray[i][j]=Phasor.copy(sum); + } + } + return cmat; + } + + // Multiply a ComplexMatrix by this PhasorMatrix + public PhasorMatrix times(ComplexMatrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.times(pmat); + } + + // Multiply a 2D array of Complex by this PhasorMatrix. + public PhasorMatrix times(Complex[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.times(pmat); + } + + // Multiply a Matrix by this PhasorMatrix. + public PhasorMatrix times(Matrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.times(pmat); + } + + // Multiply a 2D array of doubles by this PhasorMatrix. + public PhasorMatrix times(double[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.times(pmat); + } + + // Multiply this Phasor matrix by a Phasor constant + // This matrix remains unaltered + public PhasorMatrix times(Phasor constant){ + PhasorMatrix cmat = new PhasorMatrix(this.nrow, this.ncol); + Phasor [][] carray = cmat.getArrayReference(); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + carray[i][j] = this.matrix[i][j].times(constant); + } + } + return cmat; + } + + // Multiply this Phasor matrix by a real (double) constant + // This matrix remains unaltered. + public PhasorMatrix times(double constant){ + PhasorMatrix cmat = new PhasorMatrix(this.nrow, this.ncol); + Phasor [][] carray = cmat.getArrayReference(); + Phasor cconstant = new Phasor(constant, 0.0); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + carray[i][j] = this.matrix[i][j].times(cconstant); + } + } + return cmat; + } + + + // Multiply this matrix by a Phasor matrix [equivalence of *=] + public void timesEquals(PhasorMatrix bmat){ + if(this.ncol!=bmat.nrow)throw new IllegalArgumentException("Nonconformable matrices"); + + Phasor sum = new Phasor(); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<bmat.ncol; j++){ + sum=Phasor.zero(); + for(int k=0; k<this.ncol; k++){ + sum.plusEquals(this.matrix[i][k].times(bmat.matrix[k][j])); + } + this.matrix[i][j] = Phasor.copy(sum); + } + } + } + + // Multiply a 2D array of Phasors by this matrix [equivalence of *=] + public void timesEquals(Phasor[][] bmat){ + PhasorMatrix pmat = new PhasorMatrix(bmat); + this.timesEquals(pmat); + } + + // Multiply a ComplexMatrix of complex by this matrix [equivalence of *=] + public void timesEquals(ComplexMatrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.timesEquals(pmat); + } + + // Multiply a 2D array of complex by this matrix [equivalence of *=] + public void timesEquals(Complex[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.timesEquals(pmat); + } + + // Multiply a Matrix by this PhasorMatrix [equivalence of *=] + public void timesEquals(Matrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.timesEquals(pmat); + } + + // Multiply a 2D array of doubles by this matrix [equivalence of *=] + public void timesEquals(double[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.timesEquals(pmat); + } + + // Multiply this matrix by a Phasor constant [equivalence of *=] + public void timesEquals(Phasor constant){ + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + this.matrix[i][j].timesEquals(constant); + } + } + } + + // Multiply this matrix by a Complex constant [equivalence of *=] + public void timesEquals(Complex constant){ + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + this.matrix[i][j].timesEquals(constant); + } + } + } + + // Multiply this matrix by a real (double) constant [equivalence of *=] + public void timesEquals(double constant){ + Phasor cconstant = new Phasor(constant, 0.0); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + this.matrix[i][j].timesEquals(cconstant); + } + } + } + + // Multiply this matrix by a real integer(int) constant [equivalence of *=] + public void timesEquals(int constant){ + Phasor cconstant = new Phasor((double)constant, 0.0); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + this.matrix[i][j].timesEquals(cconstant); + } + } + } + + // DIVISION + // Divide this PhasorMatrix by a PhasorMatrix. + public PhasorMatrix over(PhasorMatrix bmat){ + if((this.nrow!=bmat.nrow)||(this.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + return this.times(bmat.inverse()); + } + + // Divide this matrix by a Phasor 2-D array. + public PhasorMatrix over(Phasor[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if((this.nrow!=nr)||(this.ncol!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + + PhasorMatrix cmat = new PhasorMatrix(bmat); + return this.times(cmat.inverse()); + } + + // Divide this PhasorMatrix by a ComplexMatrix. + public PhasorMatrix over(ComplexMatrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.over(pmat); + } + + // Divide this PhasorMatrix by a 2D array of Complex. + public PhasorMatrix over(Complex[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.over(pmat); + } + + // Divide this PhasorMatrix by a Matrix. + public PhasorMatrix over(Matrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.over(pmat); + } + + // Divide this PhasorMatrix by a 2D array of double. + public PhasorMatrix over(double[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + return this.over(pmat); + } + + // Divide this matrix by a PhasorMatrix [equivalence of /=] + public void overEquals(PhasorMatrix bmat){ + if((this.nrow!=bmat.nrow)||(this.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + PhasorMatrix cmat = new PhasorMatrix(bmat); + this.timesEquals(cmat.inverse()); + } + + // Divide this matrix by a 2D array of Phasors [equivalence of /=] + public void overEquals(Phasor[][] bmat){ + PhasorMatrix pmat = new PhasorMatrix(bmat); + this.overEquals(pmat); + } + + // Divide this matrix by a ComplexMatrix [equivalence of /=] + public void overEquals(ComplexMatrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.overEquals(pmat); + } + + // Divide this matrix by a 2D array of complex [equivalence of /=] + public void overEquals(Complex[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.overEquals(pmat); + } + + // Divide this PhasorMatrix a Matrix [equivalence of /=] + public void overEquals(Matrix bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.overEquals(pmat); + } + + // Divide this matrix by a 2D array of doubles [equivalence of /=] + public void overEquals(double[][] bmat){ + PhasorMatrix pmat = PhasorMatrix.toPhasorMatrix(bmat); + this.overEquals(pmat); + } + + // INVERSE + // Inverse of a square Phasor matrix + public PhasorMatrix inverse(){ + int n = this.nrow; + if(n!=this.ncol)throw new IllegalArgumentException("Matrix is not square"); + Phasor[] col = new Phasor[n]; + Phasor[] xvec = new Phasor[n]; + PhasorMatrix invmat = new PhasorMatrix(n, n); + Phasor[][] invarray = invmat.getArrayReference(); + PhasorMatrix ludmat; + + ludmat = this.luDecomp(); + for(int j=0; j<n; j++){ + for(int i=0; i<n; i++)col[i]=Phasor.zero(); + col[j]=Phasor.plusOne(); + xvec=ludmat.luBackSub(col); + for(int i=0; i<n; i++)invarray[i][j]=Phasor.copy(xvec[i]); + } + return invmat; + } + + + + // TRANSPOSE + // Transpose of a Phasor matrix + public PhasorMatrix transpose(){ + PhasorMatrix tmat = new PhasorMatrix(this.ncol, this.nrow); + Phasor[][] tarray = tmat.getArrayReference(); + for(int i=0; i<this.ncol; i++){ + for(int j=0; j<this.nrow; j++){ + tarray[i][j]=Phasor.copy(this.matrix[j][i]); + } + } + return tmat; + } + + + // COMPLEX CONJUGATE + // Complex Conjugate of a Phasor matrix + public PhasorMatrix conjugate(){ + PhasorMatrix conj = PhasorMatrix.copy(this); + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + conj.matrix[i][j]=this.matrix[i][j].conjugate(); + } + } + return conj; + } + + + // ADJOIN + // Adjoin of a Phasor matrix + public PhasorMatrix adjoin(){ + PhasorMatrix adj = PhasorMatrix.copy(this); + adj=adj.transpose(); + adj=adj.conjugate(); + return adj; + } + + + // OPPOSITE + // Opposite of a Phasor matrix + public PhasorMatrix opposite(){ + PhasorMatrix opp = PhasorMatrix.copy(this); + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + opp.matrix[i][j]=this.matrix[i][j].times(Phasor.minusOne()); + } + } + return opp; + } + + + // TRACE + // Trace of a Phasor matrix + public Phasor trace(){ + Phasor trac = new Phasor(0.0, 0.0); + for(int i=0; i<Math.min(this.ncol,this.ncol); i++){ + trac.plusEquals(this.matrix[i][i]); + } + return trac; + } + + // DETERMINANT + // Returns the determinant of a Phasor square matrix + public Phasor determinant(){ + int n = this.nrow; + if(n!=this.ncol)throw new IllegalArgumentException("Matrix is not square"); + Phasor det = new Phasor(); + PhasorMatrix ludmat; + + ludmat = this.luDecomp(); + det.reset(ludmat.dswap,0.0); + for(int j=0; j<n; j++){ + det.timesEquals(ludmat.matrix[j][j]); + } + return det; + } + + // Returns the log(determinant) of a Phasor square matrix + // Useful if determinant() underflows or overflows. + public Phasor logDeterminant(){ + int n = this.nrow; + if(n!=this.ncol)throw new IllegalArgumentException("Matrix is not square"); + Phasor det = new Phasor(); + PhasorMatrix ludmat; + + ludmat = this.luDecomp(); + det.reset(ludmat.dswap,0.0); + det=Phasor.log(det); + for(int j=0; j<n; j++){ + det.plusEquals(Phasor.log(ludmat.matrix[j][j])); + } + return det; + } + + + // FROBENIUS (EUCLIDEAN) NORM of a Phasor matrix + public double frobeniusNorm(){ + double norm=0.0D; + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + norm=Fmath.hypot(norm, matrix[i][j].abs()); + } + } + return norm; + } + + // ONE NORM of a Phasor matrix + public double oneNorm(){ + double norm=0.0D; + double sum = 0.0D; + for(int i=0; i<this.nrow; i++){ + sum=0.0D; + for(int j=0; j<this.ncol; j++){ + sum+=this.matrix[i][j].abs(); + } + norm=Math.max(norm,sum); + } + return norm; + } + + // INFINITY NORM of a Phasor matrix + public double infinityNorm(){ + double norm=0.0D; + double sum=0.0D; + for(int i=0; i<this.nrow; i++){ + sum=0.0D; + for(int j=0; j<this.ncol; j++){ + sum+=this.matrix[i][j].abs(); + } + norm=Math.max(norm,sum); + } + return norm; + } + + + // LU DECOMPOSITION OF COMPLEX MATRIX A + // For details of LU decomposition + // See Numerical Recipes, The Art of Scientific Computing + // by W H Press, S A Teukolsky, W T Vetterling & B P Flannery + // Cambridge University Press, http://www.nr.com/ + // PhasorMatrix ludmat is the returned LU decompostion + // int[] index is the vector of row permutations + // dswap returns +1.0 for even number of row interchanges + // returns -1.0 for odd number of row interchanges + public PhasorMatrix luDecomp(){ + if(this.nrow!=this.ncol)throw new IllegalArgumentException("A matrix is not square"); + int n=this.nrow; + int imax=0; + double dum=0.0D, temp=0.0D, big=0.0D; + double[] vv = new double[n]; + Phasor sum = new Phasor(); + Phasor dumm = new Phasor(); + + PhasorMatrix ludmat=PhasorMatrix.copy(this); + Phasor[][] ludarray = ludmat.getArrayReference(); + + ludmat.dswap=1.0; + for (int i=0;i<n;i++) { + big=0.0; + for (int j=0;j<n;j++){ + if ((temp=ludarray[i][j].abs()) > big) big=temp; + } + if (big == 0.0) throw new ArithmeticException("Singular matrix"); + vv[i]=1.0/big; + } + for (int j=0;j<n;j++) { + for (int i=0;i<j;i++) { + sum=Phasor.copy(ludarray[i][j]); + for (int k=0;k<i;k++) sum.minusEquals(ludarray[i][k].times(ludarray[k][j])); + ludarray[i][j]=Phasor.copy(sum); + } + big=0.0; + for (int i=j;i<n;i++) { + sum=Phasor.copy(ludarray[i][j]); + for (int k=0;k<j;k++){ + sum.minusEquals(ludarray[i][k].times(ludarray[k][j])); + } + ludarray[i][j]=Phasor.copy(sum); + if ((dum=vv[i]*sum.abs()) >= big) { + big=dum; + imax=i; + } + } + if (j != imax) { + for (int k=0;k<n;k++) { + dumm=Phasor.copy(ludarray[imax][k]); + ludarray[imax][k]=Phasor.copy(ludarray[j][k]); + ludarray[j][k]=Phasor.copy(dumm); + } + ludmat.dswap = -ludmat.dswap; + vv[imax]=vv[j]; + } + ludmat.index[j]=imax; + + if(ludarray[j][j].isZero()){ + ludarray[j][j].reset(TINY, 0.0D); + } + if(j != n-1) { + dumm=ludarray[j][j].inverse(); + for (int i=j+1;i<n;i++){ + ludarray[i][j].timesEquals(dumm); + } + } + } + return ludmat; + } + + // Solves the set of n linear Phasor equations A.X=B using not A but its LU decomposition + // Phasor bvec is the vector B (input) + // Phasor xvec is the vector X (output) + // index is the permutation vector produced by luDecomp() + public Phasor[] luBackSub(Phasor[] bvec){ + int ii=0,ip=0; + int n=bvec.length; + if(n!=this.ncol)throw new IllegalArgumentException("vector length is not equal to matrix dimension"); + if(this.ncol!=this.nrow)throw new IllegalArgumentException("matrix is not square"); + Phasor sum=new Phasor(); + Phasor[] xvec=new Phasor[n]; + for(int i=0; i<n; i++){ + xvec[i]=Phasor.copy(bvec[i]); + } + for (int i=0;i<n;i++) { + ip=this.index[i]; + sum=Phasor.copy(xvec[ip]); + xvec[ip]=Phasor.copy(xvec[i]); + if (ii==0){ + for (int j=ii;j<=i-1;j++){ + sum.minusEquals(this.matrix[i][j].times(xvec[j])); + } + } + else{ + if(sum.isZero()) ii=i; + } + xvec[i]=Phasor.copy(sum); + } + for(int i=n-1;i>=0;i--) { + sum=Phasor.copy(xvec[i]); + for (int j=i+1;j<n;j++){ + sum.minusEquals(this.matrix[i][j].times(xvec[j])); + } + xvec[i]= sum.over(this.matrix[i][i]); + } + return xvec; + } + + // Solves the set of n linear Phasor equations A.X=B + // Phasor bvec is the vector B (input) + // Phasor xvec is the vector X (output) + public Phasor[] solveLinearSet(Phasor[] bvec){ + PhasorMatrix ludmat; + + ludmat=this.luDecomp(); + return ludmat.luBackSub(bvec); + } +} + diff --git a/src/main/java/flanagan/circuits/TransmissionLine.java b/src/main/java/flanagan/circuits/TransmissionLine.java new file mode 100755 index 0000000000000000000000000000000000000000..da4b4fa714e5f3425853f3e541a0ac5ced7b57ab --- /dev/null +++ b/src/main/java/flanagan/circuits/TransmissionLine.java @@ -0,0 +1,1084 @@ +/* Class TransmisionLine +* +* Models a generalised, an ideal and a low loss transmission line +* +* Superclass for CoaxialLine, TwoWireline and ParallelPlateLine +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: July 2007 +* UPDATE 7 April 2008 +* +* DOCUMENTATION: +* See Michael T Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/TransmissionLine.html +* +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2007 - 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.circuits; + +import flanagan.complex.Complex; +import flanagan.complex.ComplexMatrix; +import flanagan.math.Fmath; +import flanagan.math.Matrix; +import flanagan.plot.PlotGraph; + +public class TransmissionLine +{ + + protected String title = "Transmission Line"; // instance title + + protected double distributedResistance = 0.0; // distributed resistance + protected double distributedConductance = 0.0; // distributed conductance + protected double distributedCapacitance = 0.0; // distributed capacitance + protected double distributedInductance = 0.0; // distributed inductance + protected Complex distributedImpedance = null; // distributed impedance + protected Complex distributedAdmittance = null; // distributed admittance + + protected Complex loadImpedance = Complex.plusInfinity(); // load impedance + // default - open line + + protected double lineLength = -1.0; // line length + protected double segmentLength = -1.0; // length of a segment of the line + + protected double frequency = 0.0; // frequency (Hz) + protected double omega = 0.0; // radial frequency + + protected Complex inputVoltage = null; // segment input voltage - harmonic excitation + protected Complex inputCurrent = null; // segment input current - harmonic excitation + + protected Complex outputVoltage = null; // segment output voltage - harmonic excitation + protected Complex outputCurrent = null; // segment output current - harmonic excitation + + protected double idealWavelength = 0.0; // wavelength on an ideal line + protected double generalWavelength = 0.0; // wavelength on a general line + protected double lowLossWavelength = 0.0; // wavelength on a low loss line + + protected double idealPhaseVelocity = 0.0; // phase velocity on an ideal line + protected double generalPhaseVelocity = 0.0; // phase velocity on a general line + protected double lowLossPhaseVelocity = 0.0; // phase velocity on a low loss line + + protected double idealGroupVelocity = 0.0; // group velocity on an ideal line + protected double generalGroupVelocity = 0.0; // group velocity on a general line + protected double lowLossGroupVelocity = 0.0; // group velocity on a low loss line + protected double delta = 1e-3; // increment in numerical differentiation + + protected double idealAttenuationConstant = 0.0; // attenuation constant of an ideal line, alpha + protected double generalAttenuationConstant = 0.0; // attenuation constant of a general line, alpha + protected double lowLossAttenuationConstant = 0.0; // attenuation constant of a low loss line, alpha + + protected double idealPhaseConstant = 0.0; // phase constant of an ideal line, beta + protected double generalPhaseConstant = 0.0; // phase constant of a general, beta + protected double lowLossPhaseConstant = 0.0; // phase constant of a low loss line, beta + + protected Complex idealPropagationConstant = null; // propagation constant of an ideal line, gamma + protected Complex generalPropagationConstant = null; // propagation constant of a general line, gamma + protected Complex lowLossPropagationConstant = null; // propagation constant of a low loss line, gamma + + protected Complex idealCharacteristicImpedance = null; // characteristic impedance, Zo, of an ideal line as Complex + protected double idealRealCharacteristicImpedance = 0.0; // characteristic impedance, Zo, of an ideal line as double + protected Complex generalCharacteristicImpedance = null; // characteristic impedance, Zo, of a general line + protected Complex lowLossCharacteristicImpedance = null; // characteristic impedance, Zo, of a low loss line + + protected Complex idealInputImpedance = null; // input impedance, Zi, of an ideal line + protected Complex generalInputImpedance = null; // input impedance, Zi, of a general line + protected Complex lowLossInputImpedance = null; // input impedance, Zi, of a low loss line + + protected Complex idealShortedLineImpedance = null; // shorted line impedance of an ideal line + protected Complex generalShortedLineImpedance = null; // shorted line impedance of a general line + protected Complex lowLossShortedLineImpedance = null; // shorted line impedance of a low loss line + + protected Complex idealOpenLineImpedance = null; // open line impedance of an ideal line + protected Complex generalOpenLineImpedance = null; // open line impedance of a general line + protected Complex lowLossOpenLineImpedance = null; // open line impedance of a low loss line + + protected Complex idealQuarterWaveLineImpedance = null; // quarter-wave line impedance of an ideal line + protected Complex generalQuarterWaveLineImpedance = null; // quarter-waveline impedance of a general line + protected Complex lowLossQuarterWaveLineImpedance = null; // quarter-wave line impedance of a low loss line + + protected Complex idealHalfWaveLineImpedance = null; // half-wave line impedance of an ideal line + protected Complex generalHalfWaveLineImpedance = null; // half-waveline impedance of a general line + protected Complex lowLossHalfWaveLineImpedance = null; // half-wave line impedance of a low loss line + + protected Complex idealRefectionCoefficient = null; // reflection coefficient of an ideal line, rho + protected Complex generalRefectionCoefficient = null; // reflection coefficient of a general line, rho + protected Complex lowLossRefectionCoefficient = null; // reflection coefficient of a low loss line, rho + + protected double idealStandingWaveRatio = 0.0; // standing wave ratio of an ideal line + protected double generalStandingWaveRatio = 0.0; // standing wave ratio of a general line + protected double lowLossStandingWaveRatio = 0.0; // standing wave ratio of a low loss line + + protected ComplexMatrix idealABCDmatrix = null; // ABCD matrix of an ideal line, as ComplexMatrix + protected ComplexMatrix generalABCDmatrix = null; // ABCD matrix of a general line, as ComplexMatrix + protected ComplexMatrix lowLossABCDmatrix = null; // ABCD matrix of a low loss line, as ComplexMatrix + + protected int numberOfPoints = 1000; // number of points used in plotting methods + + + // CONSTRUCTORS + // default title + public TransmissionLine(){ + } + + // user provided title + public TransmissionLine(String title){ + this.title = title; + } + + // INSTANCE TITLE + // reset title + public void setTitle(String title){ + this.title = title; + } + + // get title + public String getTitle(){ + return this.title; + } + + // FREQUENCY + // set frequency + public void setFrequency(double frequency){ + this.frequency = frequency; + this.omega = this.frequency * 2.0D * Math.PI; + } + + // get frequency + public double getFrequency(){ + return this.frequency; + } + + // get radial frequency + public double getRadialFrequency(){ + return this.omega; + } + + // LOAD IMPEDANCE + // set load resistor + public void setLoadImpedance(double impedance){ + this.loadImpedance = new Complex(impedance, 0.0D); + } + + // set complex load impedance + public void setLoadImpedance(Complex impedance){ + this.loadImpedance = impedance; + } + + // get complex load impedance + public Complex getLoadImpedance(){ + return this.loadImpedance; + } + + // LINE DISTANCES + // set line length + public void setLineLength(double length){ + this.lineLength = length; + } + + // get line length + public double getLineLength(){ + return this.lineLength; + } + + // set a distance along the line, z + public void setSegmentLength(double length){ + this.segmentLength = length; + } + + // SEGMENT OUTPUT VOLTAGE + // set a segment output voltage - as phasor + public void setOutputVoltage(Phasor voltage){ + this.outputVoltage = Phasor.toRectangular(voltage); + } + + // set a segment output voltage - as complex + public void setOutputVoltage(Complex voltage){ + this.outputVoltage = voltage; + } + + // set a segment output voltage - as magnitude and phase + public void setOutputVoltage(double magnitude, double phase){ + this.outputVoltage = new Complex(); + this.outputVoltage.polar(magnitude, phase); + } + + // SEGMENT OUTPUT CURRENT + // set output current - as phasor + public void setOutputCurrent(Phasor current){ + this.outputCurrent = Phasor.toRectangular(current); + } + + // set output current - as complex + public void setOutputCurrent(Complex current){ + this.outputCurrent = current; + } + + // set input current - as magnitude and phase + public void setOutputCurrent(double magnitude, double phase){ + this.outputCurrent = new Complex(); + this.outputCurrent.polar(magnitude, phase); + } + + // DISTRIBUTED PARAMETERS + // set distributed resistance + public void setDistributedResistance(double resistance){ + this.distributedResistance = resistance; + } + + // set distributed inductance + public void setDistributedInductance(double inductance){ + this.distributedInductance = inductance; + } + + // set distributed capacitance + public void setDistributedCapacitance(double capacitance){ + this.distributedCapacitance = capacitance; + } + + // set distributed conductance + public void setDistributedConductance(double conductance){ + this.distributedConductance = conductance; + } + + // get distributed resistance + public double getDistributedResistance(){ + return this.distributedResistance; + } + + // get distributed inductance + public double getDistributedInductance(){ + return this.distributedInductance; + } + + // get distributed capacitance + public double getDistributedCapacitance(){ + return this.distributedCapacitance; + } + + // get distributed conductance + public double getDistributedConductance(){ + return this.distributedConductance; + } + + // get distributed impedance + public Complex getDistributedImpedance(){ + this.distributedImpedance = new Complex(this.distributedResistance, this.distributedInductance * this.omega); + return this.distributedImpedance; + } + + // get distributed admittance + public Complex getDistributedAdmittance(){ + this.distributedAdmittance = new Complex(this.distributedConductance, this.distributedCapacitance * this.omega); + return this.distributedAdmittance; + } + + // WAVELENGTHS + // get wavelegth on a general line + public double getWavelength(){ + this.generalWavelength = this.getPhaseVelocity() / this.frequency; + return this.generalWavelength; + } + + // get wavelegth on an ideal line + public double getIdealWavelength(){ + this.idealWavelength = this.getIdealPhaseVelocity() / this.frequency; + return this.idealWavelength; + } + + // get wavelegth on a low loss line + public double getLowLossWavelength(){ + this.lowLossWavelength = this.getLowLossPhaseVelocity() / this.frequency; + return this.lowLossWavelength; + } + + // PHASE VELOCITIES + // get phase velocity on a general line + public double getPhaseVelocity(){ + this.generalPhaseVelocity = this.omega / this.getPhaseConstant(); + return this.generalPhaseVelocity; + } + + // get phase velocity of a ideal line + public double getIdealPhaseVelocity(){ + this.idealPhaseVelocity = this.omega / this.getIdealPhaseConstant(); + return this.idealPhaseVelocity; + } + + // get phase velocity of an low loss line + public double getLowLossPhaseVelocity(){ + this.lowLossPhaseVelocity = this.omega / this.getLowLossPhaseConstant(); + return this.lowLossPhaseVelocity; + } + + // GROUP VELOCITIES + // get group velocity on a general line + public double getGroupVelocity(){ + if(this.distributedResistance==0.0D && this.distributedConductance==0.0D){ + this.generalPhaseVelocity = 1.0D/Math.sqrt(this.distributedInductance * this.distributedCapacitance); + } + else{ + double omegaStored = this.omega; + this.omega = omegaStored*(1.0D - this.delta); + double betaLower = this.getPhaseConstant(); + this.omega = omegaStored*(1.0D + this.delta); + double betaUpper = this.getPhaseConstant(); + this.omega = omegaStored; + this.generalPhaseVelocity = 2.0D*this.omega*this.delta/(betaUpper - betaLower); + } + return this.generalGroupVelocity; + } + + // Set increment, delta, used in numerical integration, e.g. og general line group velocity + // default value = 1e-3 + public void setDelta(double delta){ + this.delta = delta; + } + + // get group velocity of a ideal line + public double getIdealGroupVelocity(){ + this.idealGroupVelocity = 1.0D/Math.sqrt(this.distributedInductance * this.distributedCapacitance); + return this.idealGroupVelocity; + } + + // get group velocity of an low loss line + public double getLowLossGroupVelocity(){ + double temp0 = this.omega * this.omega; + double temp1 = Math.sqrt(this.distributedInductance * this.distributedCapacitance); + double temp2 = (this.distributedResistance * this.distributedConductance) / (4.0D * temp0 * this.distributedInductance * this.distributedCapacitance); + double temp3 = (this.distributedConductance * this.distributedConductance) / (8.0D * temp0 * this.distributedCapacitance * this.distributedCapacitance); + double temp4 = (this.distributedResistance * this.distributedResistance) / (8.0D * temp0 * this.distributedInductance * this.distributedInductance); + this.lowLossPhaseConstant = 1.0/(temp1 * (1.0D + temp2 - temp3 - temp4)); + return this.lowLossGroupVelocity; + } + + // ATTENUATION CONSTANTS + // get attenuation constant, alpha, of a general line + public double getAttenuationConstant(){ + if(this.distributedResistance==0.0D && this.distributedConductance==0.0D){ + this.generalAttenuationConstant = 0.0D; + } + else{ + this.generalAttenuationConstant = Complex.sqrt(this.getDistributedImpedance().times(this.getDistributedAdmittance())).getReal(); + } + return this.generalAttenuationConstant; + } + + // get attenuation constant, alpha, of a low loss line + public double getLowLossAttenuationConstant(){ + double temp1 = Math.sqrt(this.distributedInductance / this.distributedCapacitance); + double temp2 = this.distributedResistance / (2.0D * temp1); + double temp3 = (this.distributedConductance * temp1) / 2.0D; + this.lowLossAttenuationConstant = temp2 + temp3; + return this.lowLossAttenuationConstant; + } + + // get attenuation constant, alpha, of an ideal line + public double getIdealAttenuationConstant(){ + this.idealAttenuationConstant = 0.0D; + return this.idealAttenuationConstant; + } + + // PHASE CONSTANTS + // get phase constant, beta, on a general line + public double getPhaseConstant(){ + if(this.distributedResistance==0.0D && this.distributedConductance==0.0D){ + this.generalPhaseConstant = this.omega * Math.sqrt(this.distributedInductance * this.distributedCapacitance); + } + else{ + this.generalPhaseConstant = Complex.sqrt(this.getDistributedImpedance().times(this.getDistributedAdmittance())).getImag(); + } + return this.generalPhaseConstant; + } + + // get phase constant, beta, on a low loss line + public double getLowLossPhaseConstant(){ + double temp0 = this.omega * this.omega; + double temp1 = this.omega * Math.sqrt(this.distributedInductance * this.distributedCapacitance); + double temp2 = (this.distributedResistance * this.distributedConductance) / (4.0D * temp0 * this.distributedInductance * this.distributedCapacitance); + double temp3 = (this.distributedConductance * this.distributedConductance) / (8.0D * temp0 * this.distributedCapacitance * this.distributedCapacitance); + double temp4 = (this.distributedResistance * this.distributedResistance) / (8.0D * temp0 * this.distributedInductance * this.distributedInductance); + this.lowLossPhaseConstant = temp1 * (1.0D - temp2 + temp3 + temp4); + return this.lowLossPhaseConstant; + } + + // get phase constant, beta, on an ideal line + public double getIdealPhaseConstant(){ + this.idealPhaseConstant = this.omega * Math.sqrt(this.distributedInductance * this.distributedCapacitance); + return this.idealPhaseConstant; + } + + // PROPAGATION CONSTANTS + // get propagation constant, gamma, on a general line + public Complex getPropagationConstant(){ + if(this.distributedResistance==0.0D && this.distributedConductance==0.0D){ + this.generalPropagationConstant = new Complex(0.0D, this.omega * Math.sqrt(this.distributedInductance * this.distributedCapacitance)); + } + else{ + this.generalPropagationConstant = Complex.sqrt(this.getDistributedImpedance().times(this.getDistributedAdmittance())); + } + return this.generalPropagationConstant; + } + + // get propagation constant, gamma, on a low loss line + public Complex getLowLossPropagationConstant(){ + this.lowLossPropagationConstant = new Complex(this.getLowLossAttenuationConstant(), this.getLowLossPhaseConstant()); + return this.lowLossPropagationConstant; + } + + // get propagation constant, gamma, on an ideal line + public Complex getIdealPropagationConstant(){ + this.idealPropagationConstant = new Complex(0.0D, this.omega * Math.sqrt(this.distributedInductance * this.distributedCapacitance)); + return this.idealPropagationConstant; + } + + // CHARACTERISTIC IMPEDANCES + // get characteristic impedance, Zo, of a general line + public Complex getCharacteristicImpedance(){ + this.generalCharacteristicImpedance = Complex.sqrt(this.getDistributedImpedance().over(this.getDistributedAdmittance())); + return this.generalCharacteristicImpedance; + } + + // get characteristic impedance, Zo, of a low loss line + public Complex getLowLossCharacteristicImpedance(){ + double temp0 = this.omega * this.omega; + double temp1 = Math.sqrt(this.distributedInductance / this.distributedCapacitance); + double temp2 = (this.distributedResistance * this.distributedResistance) / (8.0D * temp0 * this.distributedInductance * this.distributedInductance); + double temp3 = (this.distributedConductance * this.distributedConductance) / (8.0D * temp0 * this.distributedCapacitance * this.distributedCapacitance); + double temp4 = (this.distributedResistance * this.distributedConductance) / (4.0D * temp0 * this.distributedInductance * this.distributedCapacitance); + double temp5 = this.distributedConductance / (2D * this.omega * this.distributedCapacitance); + double temp6 = this.distributedResistance / (2D * this.omega * this.distributedInductance); + this.lowLossCharacteristicImpedance = new Complex(temp1 * (1.0D + temp2 - temp3 + temp4), temp1 * (temp5 - temp6)); + return this.lowLossCharacteristicImpedance; + } + + // get characteristic impedance, Zo, of an ideal line returned as Complex + public Complex getIdealCharacteristicImpedance(){ + this.idealRealCharacteristicImpedance = Math.sqrt(this.distributedInductance / this.distributedCapacitance); + this.idealCharacteristicImpedance = new Complex(this.idealRealCharacteristicImpedance, 0.0D); + return this.idealCharacteristicImpedance; + } + + // get characteristic impedance, Zo, of an ideal line returned as double + public double getIdealCharacteristicImpedanceAsReal(){ + this.idealRealCharacteristicImpedance = Math.sqrt(this.distributedInductance / this.distributedCapacitance); + this.idealCharacteristicImpedance = new Complex(this.idealRealCharacteristicImpedance, 0.0D); + return this.idealRealCharacteristicImpedance; + } + + // INPUT IMPEDANCES + // get input impedance, Zo, of a general line + public Complex getInputImpedance(){ + Complex gamma = this.getPropagationConstant(); + Complex zed0 = this.getCharacteristicImpedance(); + Complex temp0 = Complex.cosh(gamma.times(this.lineLength)); + Complex temp1 = Complex.sinh(gamma.times(this.lineLength)); + Complex temp2 = temp0.times(this.loadImpedance); + Complex temp3 = temp1.times(zed0); + Complex temp4 = temp0.times(zed0); + Complex temp5 = temp1.times(this.loadImpedance); + Complex temp6 = ( temp2.plus(temp3) ).over( temp4.plus(temp5) ); + this.generalInputImpedance = zed0.times(temp6); + return this.generalInputImpedance; + } + + // get input impedance, Zo, of a low loss line + public Complex getLowLossInputImpedance(){ + Complex gamma = this.getLowLossPropagationConstant(); + Complex zed0 = this.getLowLossCharacteristicImpedance(); + Complex temp0 = Complex.cosh(gamma.times(this.lineLength)); + Complex temp1 = Complex.sinh(gamma.times(this.lineLength)); + Complex temp2 = temp0.times(this.loadImpedance); + Complex temp3 = temp1.times(zed0); + Complex temp4 = temp0.times(zed0); + Complex temp5 = temp1.times(this.loadImpedance); + Complex temp6 = ( temp2.plus(temp3) ).over( temp4.plus(temp5) ); + this.lowLossInputImpedance = zed0.times(temp6); + return this.lowLossInputImpedance; + } + + // get input impedance, Zo, of an ideal line + public Complex getIdealInputImpedance(){ + double beta = this.getIdealPhaseConstant(); + double zed0 = this.getIdealCharacteristicImpedanceAsReal(); + double temp0 = Math.cos(beta*this.lineLength); + double temp1 = Math.sin(beta*this.lineLength); + Complex temp2 = ( new Complex(0.0D, temp1*zed0) ).plus(this.loadImpedance.times(temp0)); + Complex temp3 = ( new Complex(temp0*zed0, 0.0D) ).plus( Complex.plusJay().times( this.loadImpedance.times(temp1) ) ); + Complex temp4 = temp2.over(temp3); + this.idealInputImpedance = temp4.times(zed0); + return this.idealInputImpedance; + } + + // SHORTED LINE IMPEDANCES + // get shorted line impedance of a general line + public Complex getShortedLineImpedance(){ + if(this.lineLength==-1)throw new IllegalArgumentException("No line length as been entered"); + this.generalShortedLineImpedance = this.getCharacteristicImpedance().times(Complex.tanh(this.getPropagationConstant().times(this.lineLength))); + return this.generalShortedLineImpedance; + } + + // get shorted line impedance of a low loss line + public Complex getLowLossShortedLineImpedance(){ + if(this.lineLength==-1)throw new IllegalArgumentException("No line length as been entered"); + double temp0 = this.getLowLossAttenuationConstant() * this.lineLength; + double temp1 = Math.cos(this.getLowLossPhaseConstant() * this.lineLength); + double temp2 = Math.sin(this.getLowLossPhaseConstant() * this.lineLength); + Complex temp3 = new Complex(temp0 * temp1, temp2); + Complex temp4 = new Complex(temp1, temp0 * temp2); + this.lowLossShortedLineImpedance = temp3.over(temp4); + return this.lowLossShortedLineImpedance; + } + + // get shorted line impedance of an ideal line + public Complex getIdealShortedLineImpedance(){ + if(this.lineLength==-1)throw new IllegalArgumentException("No line length as been entered"); + this.idealShortedLineImpedance = new Complex(0.0D, this.getIdealCharacteristicImpedanceAsReal() * Math.tan(this.getIdealPhaseConstant() * this.lineLength)); + return this.idealShortedLineImpedance; + } + + // OPEN LINE IMPEDANCES + // get open line impedance of a general line + public Complex getOpenLineImpedance(){ + if(this.lineLength==-1)throw new IllegalArgumentException("No line length as been entered"); + this.generalShortedLineImpedance = this.getCharacteristicImpedance().times(Complex.coth(this.getPropagationConstant().times(this.lineLength))); + return this.generalShortedLineImpedance; + } + + // get open line impedance of a low loss line + public Complex getLowLossOpenLineImpedance(){ + if(this.lineLength==-1)throw new IllegalArgumentException("No line length as been entered"); + double temp0 = this.getLowLossAttenuationConstant() * this.lineLength; + double temp1 = Math.cos(this.getLowLossPhaseConstant() * this.lineLength); + double temp2 = Math.sin(this.getLowLossPhaseConstant() * this.lineLength); + Complex temp3 = new Complex(temp1, temp0 * temp2); + Complex temp4 = new Complex(temp0 * temp1, temp2); + this.lowLossShortedLineImpedance = temp3.over(temp4); + return this.lowLossShortedLineImpedance; + } + + // get open line impedance of an ideal line + public Complex getIdealOpenLineImpedance(){ + if(this.lineLength==-1)throw new IllegalArgumentException("No line length as been entered"); + this.idealShortedLineImpedance = new Complex(0.0D, -this.getIdealCharacteristicImpedanceAsReal() * Fmath.cot(this.getIdealPhaseConstant() * this.lineLength)); + return this.idealShortedLineImpedance; + } + + // QUARTER-WAVE LINE IMPEDANCES + // get quarter-wave line impedance of a general line + public Complex getQuarterWaveLineImpedance(){ + Complex alpha = new Complex(this.getAttenuationConstant(), 0.0D); + Complex zed0 = this.getCharacteristicImpedance(); + Complex temp0 = Complex.sinh(alpha.times(this.lineLength)); + Complex temp1 = Complex.cosh(alpha.times(this.lineLength)); + Complex temp2 = temp0.times(this.loadImpedance); + Complex temp3 = temp1.times(zed0); + Complex temp4 = temp0.times(zed0); + Complex temp5 = temp1.times(this.loadImpedance); + Complex temp6 = ( temp2.plus(temp3) ).over( temp4.plus(temp5) ); + this.generalQuarterWaveLineImpedance = zed0.times(temp6); + return this.generalQuarterWaveLineImpedance; + } + + // get quarter-wave line impedance of a low loss line + public Complex getLowLossQuarterWaveLineImpedance(){ + Complex alpha = new Complex(this.getLowLossAttenuationConstant(), 0.0D); + Complex zed0 = this.getLowLossCharacteristicImpedance(); + Complex temp0 = alpha.times(this.lineLength); + Complex temp1 = zed0.plus(this.loadImpedance.times(temp0)); + Complex temp2 = this.loadImpedance.plus(zed0.times(temp0)); + Complex temp3 = temp1.over(temp2); + this.lowLossQuarterWaveLineImpedance = zed0.times(temp3); + return this.lowLossQuarterWaveLineImpedance; + } + + // get quarter-wave line impedance of an ideal line + public Complex getIdealQuarterWaveLineImpedance(){ + Complex zed02 = new Complex(Fmath.square(this.getIdealCharacteristicImpedanceAsReal()), 0.0D); + this.idealQuarterWaveLineImpedance = zed02.over(this.loadImpedance); + return this.idealQuarterWaveLineImpedance; + } + + // HALF-WAVE LINE IMPEDANCES + // get half-wave line impedance of a general line + public Complex getHalfWaveLineImpedance(){ + Complex alpha = new Complex(this.getAttenuationConstant(), 0.0D); + Complex zed0 = this.getCharacteristicImpedance(); + Complex temp0 = Complex.cosh(alpha.times(this.lineLength)); + Complex temp1 = Complex.sinh(alpha.times(this.lineLength)); + Complex temp2 = temp0.times(this.loadImpedance); + Complex temp3 = temp1.times(zed0); + Complex temp4 = temp0.times(zed0); + Complex temp5 = temp1.times(this.loadImpedance); + Complex temp6 = ( temp2.plus(temp3) ).over( temp4.plus(temp5) ); + this.generalHalfWaveLineImpedance = zed0.times(temp6); + return this.generalHalfWaveLineImpedance; + } + + // get half-wave line impedance of a low loss line + public Complex getLowLossHalfWaveLineImpedance(){ + Complex alpha = new Complex(this.getLowLossAttenuationConstant(), 0.0D); + Complex zed0 = this.getLowLossCharacteristicImpedance(); + Complex temp0 = alpha.times(this.lineLength); + Complex temp1 = this.loadImpedance.plus(zed0.times(temp0)); + Complex temp2 = zed0.plus(this.loadImpedance.times(temp0)); + Complex temp3 = temp1.over(temp2); + this.lowLossHalfWaveLineImpedance = zed0.times(temp3); + return this.lowLossHalfWaveLineImpedance; + } + + // get half-wave line impedance of an ideal line + public Complex getIdealHalfWaveLineImpedance(){ + this.idealHalfWaveLineImpedance = this.loadImpedance; + return this.idealHalfWaveLineImpedance; + } + + // REFLECTION COEFFICIENTS + // get the refection coefficient, rho, of a general line + public Complex getRefectionCoefficient(){ + Complex complex1 = this.loadImpedance.minus(this.getCharacteristicImpedance()); + Complex complex2 = this.loadImpedance.plus(this.getCharacteristicImpedance()); + this.generalRefectionCoefficient = complex1.over(complex2); + return this.generalRefectionCoefficient; + } + + // get the refection coefficient, rho, of a low loss line + public Complex getLowLossRefectionCoefficient(){ + Complex complex1 = this.loadImpedance.minus(this.getLowLossCharacteristicImpedance()); + Complex complex2 = this.loadImpedance.plus(this.getLowLossCharacteristicImpedance()); + this.lowLossRefectionCoefficient = complex1.over(complex2); + return this.lowLossRefectionCoefficient; + } + + // get the refection coefficient, rho, of an ideal line + public Complex getIdealRefectionCoefficient(){ + Complex complex1 = this.loadImpedance.minus(this.getIdealCharacteristicImpedance()); + Complex complex2 = this.loadImpedance.plus(this.getIdealCharacteristicImpedance()); + this.idealRefectionCoefficient = complex1.over(complex2); + return this.idealRefectionCoefficient; + } + + // STANDING WAVE RATIOS + // get the standing wave ratio of a general line + public double getStandingWaveRatio(){ + double rho = this.getRefectionCoefficient().abs(); + this.generalStandingWaveRatio = (1.0D + rho) / (1.0D - rho); + return this.generalStandingWaveRatio; + } + + // get the standing wave ratio of a low loss line + public double getLowLossStandingWaveRatio(){ + double rho = this.getLowLossRefectionCoefficient().abs(); + this.lowLossStandingWaveRatio = (1.0D + rho) / (1.0D - rho); + return this.lowLossStandingWaveRatio; + } + + // get the standing wave ratio of an ideal line + public double getIdealStandingWaveRatio(){ + double rho = this.getIdealRefectionCoefficient().abs(); + this.idealStandingWaveRatio = (1.0D + rho) / (1.0D - rho); + return this.idealStandingWaveRatio; + } + + // ABCD MATRIX + // calculate the ABCD matrix - general line + public ComplexMatrix getABCDmatrix(){ + if(this.segmentLength==-1)throw new IllegalArgumentException("No distance along the line as been entered"); + if(this.distributedResistance==0.0D && this.distributedConductance==0.0D){ + this.generalABCDmatrix = this.getIdealABCDmatrix(); + } + else{ + this.generalABCDmatrix = new ComplexMatrix(2,2); + Complex gammal = this.getPropagationConstant().times(this.segmentLength); + Complex zed0 = this.getCharacteristicImpedance(); + this.generalABCDmatrix.setElement(0, 0, Complex.cosh(gammal)); + this.generalABCDmatrix.setElement(0, 1, Complex.sinh(gammal).times(zed0)); + this.generalABCDmatrix.setElement(1, 0, Complex.sinh(gammal).over(zed0)); + this.generalABCDmatrix.setElement(1, 1, Complex.cosh(gammal)); + } + return this.generalABCDmatrix; + } + + // calculate the ABCD matrix - ideal line + public ComplexMatrix getIdealABCDmatrix(){ + if(this.segmentLength==-1)throw new IllegalArgumentException("No distance along the line as been entered"); + + this.idealABCDmatrix = new ComplexMatrix(2,2); + double betal = this.getIdealPhaseConstant()*this.segmentLength; + double zed0 = this.getIdealCharacteristicImpedanceAsReal(); + this.idealABCDmatrix.setElement(0, 0, new Complex(Math.cos(betal), 0.0D)); + this.idealABCDmatrix.setElement(0, 1, new Complex(0.0D, Math.sin(betal)*zed0)); + this.idealABCDmatrix.setElement(1, 0, new Complex(0.0D, Math.sin(betal)/zed0)); + this.idealABCDmatrix.setElement(1, 1, new Complex(Math.cos(betal), 0.0D)); + + return this.idealABCDmatrix; + } + + // calculate the ABCD matrix - low loss line + public ComplexMatrix getLowLossABCDmatrix(){ + if(this.segmentLength==-1)throw new IllegalArgumentException("No distance along the line as been entered"); + + this.lowLossABCDmatrix = new ComplexMatrix(2,2); + Complex gammal = this.getLowLossPropagationConstant().times(this.segmentLength); + Complex zed0 = this.getLowLossCharacteristicImpedance(); + this.lowLossABCDmatrix.setElement(0, 0, Complex.cosh(gammal)); + this.lowLossABCDmatrix.setElement(0, 1, Complex.sinh(gammal).times(zed0)); + this.lowLossABCDmatrix.setElement(1, 0, Complex.sinh(gammal).over(zed0)); + this.lowLossABCDmatrix.setElement(1, 1, Complex.cosh(gammal)); + return this.lowLossABCDmatrix; + } + + // Voltage and current at start of a line segment of length segLen along the line + // given voltage and current at the start of the segment + // output as Complex + public Complex[] voltageAndCurrentAsComplex(double segLen ){ + this.segmentLength = segLen; + return voltageAndCurrentAsComplex(); + } + + // Voltage and current at start of a line segment of length segLen along the line + // given voltage and current at the start of the segment + // output as Complex + // preset segment length + public Complex[] voltageAndCurrentAsComplex(){ + Complex[] outputVector = {this.outputVoltage, this.outputCurrent}; + ComplexMatrix abcdMatrix = this.getABCDmatrix(); + Complex[] inputVector = abcdMatrix.solveLinearSet(outputVector); + this.inputVoltage = inputVector[0]; + this.inputCurrent = inputVector[1]; + return inputVector; + } + + // Voltage and current at start of a line segment of length segLen along the line + // given voltage and current at the start of the segment + // output as phasor + public Phasor[] voltageAndCurrentAsPhasor(double segLen){ + this.segmentLength = segLen; + Complex[] outputVector = {this.outputVoltage, this.outputCurrent}; + ComplexMatrix abcdMatrix = this.getABCDmatrix(); + Complex[] inputVector = abcdMatrix.solveLinearSet(outputVector); + this.inputVoltage = inputVector[0]; + this.inputCurrent = inputVector[1]; + Phasor[] input = {Phasor.toPhasor(this.inputVoltage), Phasor.toPhasor(this.inputCurrent)}; + return input; + } + + + // Voltage and current at start of a line segment of length segLen along the line + // given voltage and current at the start of the segment + // output as Phasor + // preset segment length + public Phasor[] voltageAndCurrentAsPhasor(){ + Complex[] outputVector = {this.outputVoltage, this.outputCurrent}; + ComplexMatrix abcdMatrix = this.getABCDmatrix(); + Complex[] inputVector = abcdMatrix.solveLinearSet(outputVector); + this.inputVoltage = inputVector[0]; + this.inputCurrent = inputVector[1]; + Phasor[] input = {Phasor.toPhasor(this.inputVoltage), Phasor.toPhasor(this.inputCurrent)}; + return input; + } + + // Voltage and current at start of a line segment of length segLen along the line + // given voltage and current at the start of the segment + // output as real, i.e. Magnitude.cos(phase) + public double[] voltageAndCurrentAsReal(){ + Complex[] outputVector = {this.outputVoltage, this.outputCurrent}; + ComplexMatrix abcdMatrix = this.getABCDmatrix(); + Complex[] inputVector = abcdMatrix.solveLinearSet(outputVector); + + double[] input = {inputVector[0].abs()*Math.cos(inputVector[0].arg()), inputVector[1].abs()*Math.cos(inputVector[1].arg())}; + return input; + } + + // Voltage and current at start of a line segment of length segLen along the line + // given voltage and current at the start of the segment + // output as real, i.e. Magnitude.cos(phase) + // preset segment length + public double[] voltageAndCurrentAsReal(double segLen){ + this.segmentLength = segLen; + return this.voltageAndCurrentAsReal(); + } + + // Voltage and current at start of a line segment of length segLen along the line + // given voltage and current at the start of the segment + // output as magnitude and phase + public double[] voltageAndCurrentAsMagnitudeAndPhase(){ + Complex[] outputVector = {this.outputVoltage, this.outputCurrent}; + ComplexMatrix abcdMatrix = this.getABCDmatrix(); + Complex[] inputVector = abcdMatrix.solveLinearSet(outputVector); + + double[] input = {inputVector[0].abs(), inputVector[0].arg(), inputVector[1].abs(), inputVector[1].arg()}; + return input; + } + + // Voltage and current at start of a line segment of length segLen along the line + // given voltage and current at the start of the segment + // output as magnitude and phase + // preset segment length + public double[] voltageAndCurrentAsAsMagnitudeAndPhase(double segLen){ + this.segmentLength = segLen; + return this.voltageAndCurrentAsMagnitudeAndPhase(); + } + + // Plot voltage and current along the line + public void plotVandI(){ + // Fill data arrays + double [][] data = PlotGraph.data(4, this.numberOfPoints); + + double increment = this.segmentLength/(double)(this.numberOfPoints-1); + + data[0][0] = 0.0D; + data[2][0] = 0.0D; + for(int i=1; i<this.numberOfPoints; i++){ + data[0][i] = data[0][i-1] + increment; + data[2][i] = data[2][i-1] + increment; + } + for(int i=0; i<this.numberOfPoints; i++){ + double[] output = this.voltageAndCurrentAsReal(data[0][i]); + data[1][i] = output[0]; + data[3][i] = output[1]; + } + + + data[4][0] = 0.0D; + data[6][0] = 0.0D; + data[4][1] = data[0][this.numberOfPoints/2]; + data[6][1] = data[0][this.numberOfPoints/2]; + data[4][2] = data[0][this.numberOfPoints-1]; + data[6][2] = data[0][this.numberOfPoints-1]; + + data[5][0] = data[1][0]; + data[7][0] = data[3][0]; + data[5][1] = data[1][this.numberOfPoints/2]; + data[7][1] = data[3][this.numberOfPoints/2]; + data[5][2] = data[1][this.numberOfPoints-1]; + data[7][2] = data[3][this.numberOfPoints-1]; + + // Plot data + PlotGraph pg = new PlotGraph(data); + int[] lineOpt = {3, 3, 0, 0}; + pg.setLine(lineOpt); + int[] pointOpt = {0, 0, 1, 2}; + pg.setPoint(pointOpt); + pg.setXaxisLegend("distance / metres"); + pg.setYaxisLegend("Voltage / V and Current / A"); + pg.plot(); + } + + // Deep copy + public TransmissionLine copy(){ + + if(this==null){ + return null; + } + else{ + TransmissionLine tl = new TransmissionLine(); + + tl.title = this.title; + tl.distributedResistance = this.distributedResistance; + tl.distributedConductance = this.distributedConductance; + tl.distributedCapacitance = this.distributedCapacitance; + tl.distributedInductance = this.distributedInductance; + + tl.distributedImpedance = this.distributedImpedance.copy(); + tl.distributedAdmittance = this.distributedAdmittance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.lineLength = this.lineLength; + tl.segmentLength = this.segmentLength; + tl.frequency = this.frequency; + tl.segmentLength = this.segmentLength; + tl.omega = this.omega; + + tl.inputVoltage = this.inputVoltage.copy(); + tl.inputCurrent = this.inputCurrent.copy(); + tl.outputVoltage = this.outputVoltage.copy(); + tl.outputCurrent = this.outputCurrent.copy(); + + tl.idealWavelength = this.idealWavelength; + tl.generalWavelength = this.generalWavelength; + tl.lowLossWavelength = this.lowLossWavelength; + + tl.idealPhaseVelocity = this.idealPhaseVelocity; + tl.generalPhaseVelocity = this.generalPhaseVelocity; + tl.lowLossPhaseVelocity = this.lowLossPhaseVelocity; + + tl.idealGroupVelocity = this.idealGroupVelocity; + tl.generalGroupVelocity = this.generalGroupVelocity; + tl.lowLossGroupVelocity = this.lowLossGroupVelocity; + tl.delta = this.delta; + + tl.idealAttenuationConstant = this.idealAttenuationConstant; + tl.generalAttenuationConstant = this.generalAttenuationConstant; + tl.lowLossAttenuationConstant = this.lowLossAttenuationConstant; + + tl.idealPhaseConstant = this.idealPhaseConstant; + tl.generalPhaseConstant = this.generalPhaseConstant; + tl.lowLossPhaseConstant = this.lowLossPhaseConstant; + + tl.idealPropagationConstant = this.idealPropagationConstant.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.generalPropagationConstant = this.generalPropagationConstant.copy(); + tl.lowLossPropagationConstant = this.lowLossPropagationConstant.copy(); + tl.idealCharacteristicImpedance = this.idealCharacteristicImpedance.copy(); + tl.idealRealCharacteristicImpedance = this.idealRealCharacteristicImpedance; + + tl.generalCharacteristicImpedance = this.generalCharacteristicImpedance.copy(); + tl.lowLossCharacteristicImpedance = this.lowLossCharacteristicImpedance.copy(); + tl.idealInputImpedance = this.idealInputImpedance.copy(); + tl.generalInputImpedance = this.generalInputImpedance.copy(); + tl.lowLossInputImpedance = this.lowLossInputImpedance.copy(); + + tl.idealShortedLineImpedance = this.idealShortedLineImpedance.copy(); + tl.generalShortedLineImpedance = this.generalShortedLineImpedance.copy(); + tl.lowLossShortedLineImpedance = this.lowLossShortedLineImpedance.copy(); + + tl.idealOpenLineImpedance = this.idealOpenLineImpedance.copy(); + tl.generalOpenLineImpedance = this.generalOpenLineImpedance.copy(); + tl.lowLossOpenLineImpedance = this.lowLossOpenLineImpedance.copy(); + + tl.idealQuarterWaveLineImpedance = this.idealQuarterWaveLineImpedance.copy(); + tl.generalQuarterWaveLineImpedance = this.generalQuarterWaveLineImpedance.copy(); + tl.lowLossQuarterWaveLineImpedance = this.lowLossQuarterWaveLineImpedance.copy(); + + tl.idealHalfWaveLineImpedance = this.idealHalfWaveLineImpedance.copy(); + tl.generalHalfWaveLineImpedance = this.generalHalfWaveLineImpedance.copy(); + tl.lowLossHalfWaveLineImpedance = this.lowLossHalfWaveLineImpedance.copy(); + + tl.idealRefectionCoefficient = this.idealRefectionCoefficient.copy(); + tl.generalRefectionCoefficient = this.generalRefectionCoefficient.copy(); + tl.lowLossRefectionCoefficient = this.lowLossRefectionCoefficient.copy(); + + tl.idealStandingWaveRatio = this.idealStandingWaveRatio; + tl.generalStandingWaveRatio = this.generalStandingWaveRatio; + tl.lowLossStandingWaveRatio = this.lowLossStandingWaveRatio; + + tl.idealABCDmatrix = this.idealABCDmatrix.copy(); + tl.generalABCDmatrix = this.generalABCDmatrix.copy(); + tl.lowLossABCDmatrix = this.lowLossABCDmatrix.copy(); + + tl.numberOfPoints = this.numberOfPoints; + + return tl; + } + } + + + // Clone - overrides Java.Object method clone + public Object clone(){ + + Object ret = null; + + if(this!=null){ + + TransmissionLine tl = new TransmissionLine(); + + tl.title = this.title; + tl.distributedResistance = this.distributedResistance; + tl.distributedConductance = this.distributedConductance; + tl.distributedCapacitance = this.distributedCapacitance; + tl.distributedInductance = this.distributedInductance; + + tl.distributedImpedance = this.distributedImpedance.copy(); + tl.distributedAdmittance = this.distributedAdmittance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.lineLength = this.lineLength; + tl.segmentLength = this.segmentLength; + tl.frequency = this.frequency; + tl.segmentLength = this.segmentLength; + tl.omega = this.omega; + + tl.inputVoltage = this.inputVoltage.copy(); + tl.inputCurrent = this.inputCurrent.copy(); + tl.outputVoltage = this.outputVoltage.copy(); + tl.outputCurrent = this.outputCurrent.copy(); + + tl.idealWavelength = this.idealWavelength; + tl.generalWavelength = this.generalWavelength; + tl.lowLossWavelength = this.lowLossWavelength; + + tl.idealPhaseVelocity = this.idealPhaseVelocity; + tl.generalPhaseVelocity = this.generalPhaseVelocity; + tl.lowLossPhaseVelocity = this.lowLossPhaseVelocity; + + tl.idealGroupVelocity = this.idealGroupVelocity; + tl.generalGroupVelocity = this.generalGroupVelocity; + tl.lowLossGroupVelocity = this.lowLossGroupVelocity; + tl.delta = this.delta; + + tl.idealAttenuationConstant = this.idealAttenuationConstant; + tl.generalAttenuationConstant = this.generalAttenuationConstant; + tl.lowLossAttenuationConstant = this.lowLossAttenuationConstant; + + tl.idealPhaseConstant = this.idealPhaseConstant; + tl.generalPhaseConstant = this.generalPhaseConstant; + tl.lowLossPhaseConstant = this.lowLossPhaseConstant; + + tl.idealPropagationConstant = this.idealPropagationConstant.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.generalPropagationConstant = this.generalPropagationConstant.copy(); + tl.lowLossPropagationConstant = this.lowLossPropagationConstant.copy(); + tl.idealCharacteristicImpedance = this.idealCharacteristicImpedance.copy(); + tl.idealRealCharacteristicImpedance = this.idealRealCharacteristicImpedance; + + tl.generalCharacteristicImpedance = this.generalCharacteristicImpedance.copy(); + tl.lowLossCharacteristicImpedance = this.lowLossCharacteristicImpedance.copy(); + tl.idealInputImpedance = this.idealInputImpedance.copy(); + tl.generalInputImpedance = this.generalInputImpedance.copy(); + tl.lowLossInputImpedance = this.lowLossInputImpedance.copy(); + + tl.idealShortedLineImpedance = this.idealShortedLineImpedance.copy(); + tl.generalShortedLineImpedance = this.generalShortedLineImpedance.copy(); + tl.lowLossShortedLineImpedance = this.lowLossShortedLineImpedance.copy(); + + tl.idealOpenLineImpedance = this.idealOpenLineImpedance.copy(); + tl.generalOpenLineImpedance = this.generalOpenLineImpedance.copy(); + tl.lowLossOpenLineImpedance = this.lowLossOpenLineImpedance.copy(); + + tl.idealQuarterWaveLineImpedance = this.idealQuarterWaveLineImpedance.copy(); + tl.generalQuarterWaveLineImpedance = this.generalQuarterWaveLineImpedance.copy(); + tl.lowLossQuarterWaveLineImpedance = this.lowLossQuarterWaveLineImpedance.copy(); + + tl.idealHalfWaveLineImpedance = this.idealHalfWaveLineImpedance.copy(); + tl.generalHalfWaveLineImpedance = this.generalHalfWaveLineImpedance.copy(); + tl.lowLossHalfWaveLineImpedance = this.lowLossHalfWaveLineImpedance.copy(); + + tl.idealRefectionCoefficient = this.idealRefectionCoefficient.copy(); + tl.generalRefectionCoefficient = this.generalRefectionCoefficient.copy(); + tl.lowLossRefectionCoefficient = this.lowLossRefectionCoefficient.copy(); + + tl.idealStandingWaveRatio = this.idealStandingWaveRatio; + tl.generalStandingWaveRatio = this.generalStandingWaveRatio; + tl.lowLossStandingWaveRatio = this.lowLossStandingWaveRatio; + + tl.idealABCDmatrix = this.idealABCDmatrix.copy(); + tl.generalABCDmatrix = this.generalABCDmatrix.copy(); + tl.lowLossABCDmatrix = this.lowLossABCDmatrix.copy(); + + tl.numberOfPoints = this.numberOfPoints; + + ret = (Object)tl; + } + return ret; + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/circuits/TwoWireLine.java b/src/main/java/flanagan/circuits/TwoWireLine.java new file mode 100755 index 0000000000000000000000000000000000000000..04a7959cd2451b92bef2ad007a85d838d91fd3a7 --- /dev/null +++ b/src/main/java/flanagan/circuits/TwoWireLine.java @@ -0,0 +1,305 @@ +/* Class TwoWireLine +* +* Models a two parallel wire transmision line +* This is a subclass of the superclass TransmissionLine +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: June 2007 +* UPDATE: 7 April 2008 +* +* DOCUMENTATION: +* See Michael T Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/TwoWireLine.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/TransmissionLine.html +* +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2007 - 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.circuits; + +import flanagan.complex.Complex; + +public class TwoWireLine extends TransmissionLine{ + + private double wireRadius = -1.0D; // wire radius - both wires have the same radius + private double wireSeparation = -1.0D; // wire separation - wire centre to wire centre + private boolean distancesSet = false; // = true when both wire radius and separation entered + + private double relativePermittivity = 1.0D; // relative electrical permittivity of the material around the conductors + private double relativePermeability = 1.0D; // relative magnetic permeability of the material around the conductors + + + // CONSTRUCTOR + public TwoWireLine(){ + } + + // WIRE RADII + // Set wire radius - both wires identical + public void setWireRadius(double radius){ + if(radius<=0.0D)throw new IllegalArgumentException("The wire radius, " + radius + ", must be greater than zero"); + if(this.wireSeparation!=-1.0D && this.wireSeparation<=2.0D*radius)throw new IllegalArgumentException("The wire separation distance, " + this.wireSeparation + ", must be greater than the sum of the two wire radii, " + 2.0D*radius); + this.wireRadius = radius; + if(this.wireSeparation!=-1.0)this.distancesSet = true; + if(this.distancesSet)this.calculateDistributedCapacitanceAndInductance(); + } + + // WIRE SEPARATION + // Set wire separation - wire centre to wire centre + public void setWireSeparation(double separation){ + if(separation<=0.0D)throw new IllegalArgumentException("The wire separation, " + separation + ", must be greater than zero"); + if(this.wireRadius!=-1.0D && separation<=2.0D*this.wireRadius)throw new IllegalArgumentException("The wire separation distance, " + separation + ", must be greater than the sum of the two wire radii, " + 2.0D*this.wireRadius); + this.wireSeparation = separation; + if(this.wireRadius!=-1.0)this.distancesSet = true; + if(this.distancesSet)this.calculateDistributedCapacitanceAndInductance(); + } + + // PERMITTIVITY + // Set relative electrical permittivity of the material around the conductors + public void setRelativePermittivity(double epsilonR){ + this.relativePermittivity = epsilonR; + if(this.distancesSet)this.calculateDistributedCapacitanceAndInductance(); + } + + // PERMEABILTY + // Set relative magnetic permeability of the material around the conductors + public void setRelativePermeability(double muR){ + this.relativePermeability = muR; + if(this.distancesSet)this.calculateDistributedCapacitanceAndInductance(); + } + + // CALCULATE DISTRIBUTED PARAMETERS + private void calculateDistributedCapacitanceAndInductance(){ + super.distributedCapacitance = Impedance.parallelWiresCapacitance(1.0D, this.wireRadius, this.wireSeparation, this.relativePermittivity); + super.distributedInductance = Impedance.parallelWiresInductance(1.0D, this.wireRadius, this.wireSeparation, this.relativePermeability); + } + + // DEEP COPY + public TwoWireLine copy(){ + + if(this==null){ + return null; + } + else{ + TwoWireLine tl = new TwoWireLine(); + + tl.wireRadius = this.wireRadius; + tl.wireSeparation = this.wireSeparation; + tl.distancesSet = this.distancesSet; + tl.relativePermittivity = this.relativePermittivity; + tl.relativePermeability = this.relativePermeability; + + tl.title = this.title; + tl.distributedResistance = this.distributedResistance; + tl.distributedConductance = this.distributedConductance; + tl.distributedCapacitance = this.distributedCapacitance; + tl.distributedInductance = this.distributedInductance; + + tl.distributedImpedance = this.distributedImpedance.copy(); + tl.distributedAdmittance = this.distributedAdmittance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.lineLength = this.lineLength; + tl.segmentLength = this.segmentLength; + tl.frequency = this.frequency; + tl.segmentLength = this.segmentLength; + tl.omega = this.omega; + + tl.inputVoltage = this.inputVoltage.copy(); + tl.inputCurrent = this.inputCurrent.copy(); + tl.outputVoltage = this.outputVoltage.copy(); + tl.outputCurrent = this.outputCurrent.copy(); + + tl.idealWavelength = this.idealWavelength; + tl.generalWavelength = this.generalWavelength; + tl.lowLossWavelength = this.lowLossWavelength; + + tl.idealPhaseVelocity = this.idealPhaseVelocity; + tl.generalPhaseVelocity = this.generalPhaseVelocity; + tl.lowLossPhaseVelocity = this.lowLossPhaseVelocity; + + tl.idealGroupVelocity = this.idealGroupVelocity; + tl.generalGroupVelocity = this.generalGroupVelocity; + tl.lowLossGroupVelocity = this.lowLossGroupVelocity; + tl.delta = this.delta; + + tl.idealAttenuationConstant = this.idealAttenuationConstant; + tl.generalAttenuationConstant = this.generalAttenuationConstant; + tl.lowLossAttenuationConstant = this.lowLossAttenuationConstant; + + tl.idealPhaseConstant = this.idealPhaseConstant; + tl.generalPhaseConstant = this.generalPhaseConstant; + tl.lowLossPhaseConstant = this.lowLossPhaseConstant; + + tl.idealPropagationConstant = this.idealPropagationConstant.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.generalPropagationConstant = this.generalPropagationConstant.copy(); + tl.lowLossPropagationConstant = this.lowLossPropagationConstant.copy(); + tl.idealCharacteristicImpedance = this.idealCharacteristicImpedance.copy(); + tl.idealRealCharacteristicImpedance = this.idealRealCharacteristicImpedance; + + tl.generalCharacteristicImpedance = this.generalCharacteristicImpedance.copy(); + tl.lowLossCharacteristicImpedance = this.lowLossCharacteristicImpedance.copy(); + tl.idealInputImpedance = this.idealInputImpedance.copy(); + tl.generalInputImpedance = this.generalInputImpedance.copy(); + tl.lowLossInputImpedance = this.lowLossInputImpedance.copy(); + + tl.idealShortedLineImpedance = this.idealShortedLineImpedance.copy(); + tl.generalShortedLineImpedance = this.generalShortedLineImpedance.copy(); + tl.lowLossShortedLineImpedance = this.lowLossShortedLineImpedance.copy(); + + tl.idealOpenLineImpedance = this.idealOpenLineImpedance.copy(); + tl.generalOpenLineImpedance = this.generalOpenLineImpedance.copy(); + tl.lowLossOpenLineImpedance = this.lowLossOpenLineImpedance.copy(); + + tl.idealQuarterWaveLineImpedance = this.idealQuarterWaveLineImpedance.copy(); + tl.generalQuarterWaveLineImpedance = this.generalQuarterWaveLineImpedance.copy(); + tl.lowLossQuarterWaveLineImpedance = this.lowLossQuarterWaveLineImpedance.copy(); + + tl.idealHalfWaveLineImpedance = this.idealHalfWaveLineImpedance.copy(); + tl.generalHalfWaveLineImpedance = this.generalHalfWaveLineImpedance.copy(); + tl.lowLossHalfWaveLineImpedance = this.lowLossHalfWaveLineImpedance.copy(); + + tl.idealRefectionCoefficient = this.idealRefectionCoefficient.copy(); + tl.generalRefectionCoefficient = this.generalRefectionCoefficient.copy(); + tl.lowLossRefectionCoefficient = this.lowLossRefectionCoefficient.copy(); + + tl.idealStandingWaveRatio = this.idealStandingWaveRatio; + tl.generalStandingWaveRatio = this.generalStandingWaveRatio; + tl.lowLossStandingWaveRatio = this.lowLossStandingWaveRatio; + + tl.idealABCDmatrix = this.idealABCDmatrix.copy(); + tl.generalABCDmatrix = this.generalABCDmatrix.copy(); + tl.lowLossABCDmatrix = this.lowLossABCDmatrix.copy(); + + tl.numberOfPoints = this.numberOfPoints; + + return tl; + } + } + + + // Clone - overrides Java.Object method clone + public Object clone(){ + + Object ret = null; + + if(this!=null){ + + TwoWireLine tl = new TwoWireLine(); + + tl.wireRadius = this.wireRadius; + tl.wireSeparation = this.wireSeparation; + tl.distancesSet = this.distancesSet; + tl.relativePermittivity = this.relativePermittivity; + tl.relativePermeability = this.relativePermeability; + + tl.title = this.title; + tl.distributedResistance = this.distributedResistance; + tl.distributedConductance = this.distributedConductance; + tl.distributedCapacitance = this.distributedCapacitance; + tl.distributedInductance = this.distributedInductance; + + tl.distributedImpedance = this.distributedImpedance.copy(); + tl.distributedAdmittance = this.distributedAdmittance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.lineLength = this.lineLength; + tl.segmentLength = this.segmentLength; + tl.frequency = this.frequency; + tl.segmentLength = this.segmentLength; + tl.omega = this.omega; + + tl.inputVoltage = this.inputVoltage.copy(); + tl.inputCurrent = this.inputCurrent.copy(); + tl.outputVoltage = this.outputVoltage.copy(); + tl.outputCurrent = this.outputCurrent.copy(); + + tl.idealWavelength = this.idealWavelength; + tl.generalWavelength = this.generalWavelength; + tl.lowLossWavelength = this.lowLossWavelength; + + tl.idealPhaseVelocity = this.idealPhaseVelocity; + tl.generalPhaseVelocity = this.generalPhaseVelocity; + tl.lowLossPhaseVelocity = this.lowLossPhaseVelocity; + + tl.idealGroupVelocity = this.idealGroupVelocity; + tl.generalGroupVelocity = this.generalGroupVelocity; + tl.lowLossGroupVelocity = this.lowLossGroupVelocity; + tl.delta = this.delta; + + tl.idealAttenuationConstant = this.idealAttenuationConstant; + tl.generalAttenuationConstant = this.generalAttenuationConstant; + tl.lowLossAttenuationConstant = this.lowLossAttenuationConstant; + + tl.idealPhaseConstant = this.idealPhaseConstant; + tl.generalPhaseConstant = this.generalPhaseConstant; + tl.lowLossPhaseConstant = this.lowLossPhaseConstant; + + tl.idealPropagationConstant = this.idealPropagationConstant.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + tl.loadImpedance = this.loadImpedance.copy(); + + tl.generalPropagationConstant = this.generalPropagationConstant.copy(); + tl.lowLossPropagationConstant = this.lowLossPropagationConstant.copy(); + tl.idealCharacteristicImpedance = this.idealCharacteristicImpedance.copy(); + tl.idealRealCharacteristicImpedance = this.idealRealCharacteristicImpedance; + + tl.generalCharacteristicImpedance = this.generalCharacteristicImpedance.copy(); + tl.lowLossCharacteristicImpedance = this.lowLossCharacteristicImpedance.copy(); + tl.idealInputImpedance = this.idealInputImpedance.copy(); + tl.generalInputImpedance = this.generalInputImpedance.copy(); + tl.lowLossInputImpedance = this.lowLossInputImpedance.copy(); + + tl.idealShortedLineImpedance = this.idealShortedLineImpedance.copy(); + tl.generalShortedLineImpedance = this.generalShortedLineImpedance.copy(); + tl.lowLossShortedLineImpedance = this.lowLossShortedLineImpedance.copy(); + + tl.idealOpenLineImpedance = this.idealOpenLineImpedance.copy(); + tl.generalOpenLineImpedance = this.generalOpenLineImpedance.copy(); + tl.lowLossOpenLineImpedance = this.lowLossOpenLineImpedance.copy(); + + tl.idealQuarterWaveLineImpedance = this.idealQuarterWaveLineImpedance.copy(); + tl.generalQuarterWaveLineImpedance = this.generalQuarterWaveLineImpedance.copy(); + tl.lowLossQuarterWaveLineImpedance = this.lowLossQuarterWaveLineImpedance.copy(); + + tl.idealHalfWaveLineImpedance = this.idealHalfWaveLineImpedance.copy(); + tl.generalHalfWaveLineImpedance = this.generalHalfWaveLineImpedance.copy(); + tl.lowLossHalfWaveLineImpedance = this.lowLossHalfWaveLineImpedance.copy(); + + tl.idealRefectionCoefficient = this.idealRefectionCoefficient.copy(); + tl.generalRefectionCoefficient = this.generalRefectionCoefficient.copy(); + tl.lowLossRefectionCoefficient = this.lowLossRefectionCoefficient.copy(); + + tl.idealStandingWaveRatio = this.idealStandingWaveRatio; + tl.generalStandingWaveRatio = this.generalStandingWaveRatio; + tl.lowLossStandingWaveRatio = this.lowLossStandingWaveRatio; + + tl.idealABCDmatrix = this.idealABCDmatrix.copy(); + tl.generalABCDmatrix = this.generalABCDmatrix.copy(); + tl.lowLossABCDmatrix = this.lowLossABCDmatrix.copy(); + + tl.numberOfPoints = this.numberOfPoints; + + ret = (Object)tl; + } + return ret; + } +} diff --git a/src/main/java/flanagan/complex/Complex.java b/src/main/java/flanagan/complex/Complex.java new file mode 100755 index 0000000000000000000000000000000000000000..e73ad0b5746ef6766c92a4d6d40251ca1ce05681 --- /dev/null +++ b/src/main/java/flanagan/complex/Complex.java @@ -0,0 +1,2325 @@ +/* +* Class Complex +* +* Defines a complex number as an object and includes +* the methods needed for standard complex arithmetic +* +* See class ComplexMatrix for complex matrix manipulations +* See class ComplexPoly for complex polynomial manipulations +* See class ComplexErrorProp for the error propogation in complex arithmetic +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: February 2002 +* UPDATED: 1 August 2006, 29 April 2007, 15,21,22 June 2007, 22 November 2007 +* 20 May 2008, 26 August 2008, 9 November 2009 +* +* DOCUMENTATION: +* See Michael T Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Complex.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + + +package flanagan.complex; + +import flanagan.math.Fmath; + +public class Complex{ + + private double real = 0.0D; // Real part of a complex number + private double imag = 0.0D; // Imaginary part of a complex number + private static char jori = 'j'; // i or j in a + j.b or a + i.b representaion + // default value = j + private static boolean infOption = true; // option determining how infinity is handled + // if true (default option): + // multiplication with either complex number with either part = infinity returns infinity + // unless the one complex number is zero in both parts + // division by a complex number with either part = infinity returns zero + // unless the dividend is also infinite in either part + // if false: + // standard arithmetic performed + + +/*********************************************************/ + + // CONSTRUCTORS + // default constructor - real and imag = zero + public Complex() + { + this.real = 0.0D; + this.imag = 0.0D; + } + + // constructor - initialises both real and imag + public Complex(double real, double imag) + { + this.real = real; + this.imag = imag; + } + + // constructor - initialises real, imag = 0.0 + public Complex(double real) + { + this.real = real; + this.imag = 0.0D; + } + + // constructor - initialises both real and imag to the values of an existing Complex + public Complex(Complex c) + { + this.real = c.real; + this.imag = c.imag; + } + +/*********************************************************/ + + // PUBLIC METHODS + + // SET VALUES + // Set the value of real + public void setReal(double real){ + this.real = real; + } + // Set the value of imag + public void setImag(double imag){ + this.imag = imag; + } + + // Set the values of real and imag + public void reset(double real, double imag){ + this.real = real; + this.imag = imag; + } + + // Set real and imag given the modulus and argument (in radians) + public void polarRad(double mod, double arg){ + this.real = mod*Math.cos(arg); + this.imag = mod*Math.sin(arg); + } + + // Set real and imag given the modulus and argument (in radians) + // retained for compatibility + public void polar(double mod, double arg){ + this.real = mod*Math.cos(arg); + this.imag = mod*Math.sin(arg); + } + + // Set real and imag given the modulus and argument (in degrees) + public void polarDeg(double mod, double arg){ + arg = Math.toRadians(arg); + this.real = mod*Math.cos(arg); + this.imag = mod*Math.sin(arg); + } + + // GET VALUES + // Get the value of real + public double getReal(){ + return real; + } + + // Get the value of imag + public double getImag(){ + return imag; + } + + // INPUT AND OUTPUT + + // READ A COMPLEX NUMBER + // Read a complex number from the keyboard console after a prompt message + // in a String format compatible with Complex.parse, + // e.g 2+j3, 2 + j3, 2+i3, 2 + i3 + // prompt = Prompt message to vdu + public static final synchronized Complex readComplex(String prompt) + { + int ch = ' '; + String cstring = ""; + boolean done = false; + + System.out.print(prompt + " "); + System.out.flush(); + + while (!done){ + try{ + ch = System.in.read(); + if (ch < 0 || (char)ch == '\n') + done = true; + else + cstring = cstring + (char) ch; + } + catch(java.io.IOException e){ + done = true; + } + } + return Complex.parseComplex(cstring); + } + + // Read a complex number from the keyboard console after a prompt message (with String default option) + // in a String format compatible with Complex.parse, + // e.g 2+j3, 2 + j3, 2+i3, 2 + i3 + // prompt = Prompt message to vdu + // dflt = default value + public static final synchronized Complex readComplex(String prompt, String dflt) + { + int ch = ' '; + String cstring = ""; + boolean done = false; + + System.out.print(prompt + " [default value = " + dflt + "] "); + System.out.flush(); + + int i=0; + while (!done){ + try{ + ch = System.in.read(); + if (ch < 0 || (char)ch == '\n' || (char)ch =='\r'){ + if(i==0){ + cstring = dflt; + if((char)ch == '\r')ch = System.in.read(); + } + done = true; + } + else{ + cstring = cstring + (char) ch; + i++; + } + } + catch(java.io.IOException e){ + done = true; + } + } + return Complex.parseComplex(cstring); + } + + // Read a complex number from the keyboard console after a prompt message (with Complex default option) + // in a String format compatible with Complex.parse, + // e.g 2+j3, 2 + j3, 2+i3, 2 + i3 + // prompt = Prompt message to vdu + // dflt = default value + public static final synchronized Complex readComplex(String prompt, Complex dflt) + { + int ch = ' '; + String cstring = ""; + boolean done = false; + + System.out.print(prompt + " [default value = " + dflt + "] "); + System.out.flush(); + + int i=0; + while (!done){ + try{ + ch = System.in.read(); + if (ch < 0 || (char)ch == '\n' || (char)ch =='\r'){ + if(i==0){ + if((char)ch == '\r')ch = System.in.read(); + return dflt; + } + done = true; + } + else{ + cstring = cstring + (char) ch; + i++; + } + } + catch(java.io.IOException e){ + done = true; + } + } + return Complex.parseComplex(cstring); + } + + + + // Read a complex number from the keyboard console without a prompt message + // in a String format compatible with Complex.parse, + // e.g 2+j3, 2 + j3, 2+i3, 2 + i3 + // prompt = Prompt message to vdu + public static final synchronized Complex readComplex() + { + int ch = ' '; + String cstring = ""; + boolean done = false; + + System.out.print(" "); + System.out.flush(); + + while (!done){ + try{ + ch = System.in.read(); + if (ch < 0 || (char)ch == '\n') + done = true; + else + cstring = cstring + (char) ch; + } + catch(java.io.IOException e){ + done = true; + } + } + return Complex.parseComplex(cstring); + } + + // PRINT A COMPLEX NUMBER + // Print to terminal window with text (message) and a line return + public void println(String message){ + System.out.println(message + " " + this.toString()); + } + + // Print to terminal window without text (message) but with a line return + public void println(){ + System.out.println(" " + this.toString()); + } + + // Print to terminal window with text (message) but without line return + public void print(String message){ + System.out.print(message + " " + this.toString()); + } + + // Print to terminal window without text (message) and without line return + public void print(){ + System.out.print(" " + this.toString()); + } + + // PRINT AN ARRAY OF COMLEX NUMBERS + // Print an array to terminal window with text (message) and a line return + public static void println(String message, Complex[] aa){ + System.out.println(message); + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i].toString() + " "); + } + } + + // Print an array to terminal window without text (message) but with a line return + public static void println(Complex[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i].toString() + " "); + } + } + + // Print an array to terminal window with text (message) but no line returns except at the end + public static void print(String message, Complex[] aa){ + System.out.print(message+ " "); + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i].toString() + " "); + } + System.out.println(); + } + + // Print an array to terminal window without text (message) but with no line returns except at the end + public static void print(Complex[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i].toString() + " "); + } + System.out.println(); + } + + // TRUNCATION + // Rounds the mantissae of both the real and imaginary parts of Complex to prec places + // Static method + public static Complex truncate(Complex x, int prec){ + if(prec<0)return x; + + double xR = x.getReal(); + double xI = x.getImag(); + Complex y = new Complex(); + + xR = Fmath.truncate(xR, prec); + xI = Fmath.truncate(xI, prec); + + y.reset(xR, xI); + + return y; + } + + // instance method + public Complex truncate(int prec){ + if(prec<0)return this; + + double xR = this.getReal(); + double xI = this.getImag(); + Complex y = new Complex(); + + xR = Fmath.truncate(xR, prec); + xI = Fmath.truncate(xI, prec); + + y.reset(xR, xI); + + return y; + } + + + // CONVERSIONS + // Format a complex number as a string, a + jb or a + ib[instance method] + // < value of real > < + or - > < j or i> < value of imag > + // Choice of j or i is set by Complex.seti() or Complex.setj() + // j is the default option for j or i + // Overides java.lang.String.toString() + public String toString(){ + char ch='+'; + if(this.imag<0.0D)ch='-'; + return this.real+" "+ch+" "+jori+Math.abs(this.imag); + } + + // Format a complex number as a string, a + jb or a + ib [static method] + // See static method above for comments + public static String toString(Complex aa){ + char ch='+'; + if(aa.imag<0.0D)ch='-'; + return aa.real+" "+ch+jori+Math.abs(aa.imag); + } + + // Sets the representation of the square root of minus one to j in Strings + public static void setj(){ + jori = 'j'; + } + + // Sets the representation of the square root of minus one to i in Strings + public static void seti(){ + jori = 'i'; + } + + // Returns the representation of the square root of minus one (j or i) set for Strings + public static char getjori(){ + return jori; + } + + // Parse a string to obtain Complex + // accepts strings 'real''s''sign''s''x''imag' + // where x may be i or j and s may be no spaces or any number of spaces + // and sign may be + or - + // e.g. 2+j3, 2 + j3, 2+i3, 2 + i3 + public static Complex parseComplex(String ss){ + Complex aa = new Complex(); + ss = ss.trim(); + double first = 1.0D; + if(ss.charAt(0)=='-'){ + first = -1.0D; + ss = ss.substring(1); + } + + int i = ss.indexOf('j'); + if(i==-1){ + i = ss.indexOf('i'); + } + if(i==-1)throw new NumberFormatException("no i or j found"); + + int imagSign=1; + int j = ss.indexOf('+'); + + if(j==-1){ + j = ss.indexOf('-'); + if(j>-1) imagSign=-1; + } + if(j==-1)throw new NumberFormatException("no + or - found"); + + int r0=0; + int r1=j; + int i0=i+1; + int i1=ss.length(); + String sreal=ss.substring(r0,r1); + String simag=ss.substring(i0,i1); + aa.real=first*Double.parseDouble(sreal); + aa.imag=imagSign*Double.parseDouble(simag); + return aa; + } + + // Same method as parseComplex + // Overides java.lang.Object.valueOf() + public static Complex valueOf(String ss){ + return Complex.parseComplex(ss); + } + + // Return a HASH CODE for the Complex number + // Overides java.lang.Object.hashCode() + public int hashCode() + { + long lreal = Double.doubleToLongBits(this.real); + long limag = Double.doubleToLongBits(this.imag); + int hreal = (int)(lreal^(lreal>>>32)); + int himag = (int)(limag^(limag>>>32)); + return 7*(hreal/10)+3*(himag/10); + } + + // SWAP + // Swaps two complex numbers + public static void swap(Complex aa, Complex bb){ + double holdAreal = aa.real; + double holdAimag = aa.imag; + aa.reset(bb.real, bb.imag); + bb.reset(holdAreal, holdAimag); + } + + + // ARRAYS + + // Create a one dimensional array of Complex objects of length n + // all real = 0 and all imag = 0 + public static Complex[] oneDarray(int n){ + Complex[] a =new Complex[n]; + for(int i=0; i<n; i++){ + a[i]=Complex.zero(); + } + return a; + } + + // Create a one dimensional array of Complex objects of length n + // all real = a and all imag = b + public static Complex[] oneDarray(int n, double a, double b){ + Complex[] c =new Complex[n]; + for(int i=0; i<n; i++){ + c[i]=Complex.zero(); + c[i].reset(a, b); + } + return c; + } + + // Arithmetic mean of a one dimensional array of complex numbers + public static Complex mean(Complex[] aa){ + int n = aa.length; + Complex sum = new Complex(0.0D, 0.0D); + for(int i=0; i<n; i++){ + sum = sum.plus(aa[i]); + } + return sum.over((double)n); + } + + // Create a one dimensional array of Complex objects of length n + // all = the Complex constant + public static Complex[] oneDarray(int n, Complex constant){ + Complex[] c =new Complex[n]; + for(int i=0; i<n; i++){ + c[i]=Complex.copy(constant); + } + return c; + } + + // Create a two dimensional array of Complex objects of dimensions n and m + // all real = zero and all imag = zero + public static Complex[][] twoDarray(int n, int m){ + Complex[][] a =new Complex[n][m]; + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + a[i][j]=Complex.zero(); + } + } + return a; + } + + // Create a two dimensional array of Complex objects of dimensions n and m + // all real = a and all imag = b + public static Complex[][] twoDarray(int n, int m, double a, double b){ + Complex[][] c =new Complex[n][m]; + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + c[i][j]=Complex.zero(); + c[i][j].reset(a, b); + } + } + return c; + } + + // Create a two dimensional array of Complex objects of dimensions n and m + // all = the Complex constant + public static Complex[][] twoDarray(int n, int m, Complex constant){ + Complex[][] c =new Complex[n][m]; + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + c[i][j]=Complex.copy(constant); + } + } + return c; + } + + // Create a three dimensional array of Complex objects of dimensions n, m and l + // all real = zero and all imag = zero + public static Complex[][][] threeDarray(int n, int m, int l){ + Complex[][][] a =new Complex[n][m][l]; + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + for(int k=0; k<l; k++){ + a[i][j][k]=Complex.zero(); + } + } + } + return a; + } + + // Create a three dimensional array of Complex objects of dimensions n, m and l + // all real = a and all imag = b + public static Complex[][][] threeDarray(int n, int m, int l, double a, double b){ + Complex[][][] c =new Complex[n][m][l]; + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + for(int k=0; k<l; k++){ + c[i][j][k]=Complex.zero(); + c[i][j][k].reset(a, b); + } + } + } + return c; + } + + // Create a three dimensional array of Complex objects of dimensions n, m and l + // all = the Complex constant + public static Complex[][][] threeDarray(int n, int m, int l, Complex constant){ + Complex[][][] c =new Complex[n][m][l]; + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + for(int k=0; k<l; k++){ + c[i][j][k]=Complex.copy(constant); + } + } + } + return c; + } + + // COPY + // Copy a single complex number [static method] + public static Complex copy(Complex a){ + if(a==null){ + return null; + } + else{ + Complex b = new Complex(); + b.real=a.real; + b.imag=a.imag; + return b; + } + } + + // Copy a single complex number [instance method] + public Complex copy(){ + if(this==null){ + return null; + } + else{ + Complex b = new Complex(); + b.real=this.real; + b.imag=this.imag; + return b; + } + } + + + // Copy a 1D array of complex numbers (deep copy) + // static metod + public static Complex[] copy(Complex[] a){ + if(a==null){ + return null; + } + else{ + int n =a.length; + Complex[] b = Complex.oneDarray(n); + for(int i=0; i<n; i++){ + b[i]=Complex.copy(a[i]); + } + return b; + } + } + + // Copy a 2D array of complex numbers (deep copy) + public static Complex[][] copy(Complex[][] a){ + if(a==null){ + return null; + } + else{ + int n =a.length; + int m =a[0].length; + Complex[][] b = Complex.twoDarray(n, m); + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + b[i][j]=Complex.copy(a[i][j]); + } + } + return b; + } + } + + // Copy a 3D array of complex numbers (deep copy) + public static Complex[][][] copy(Complex[][][] a){ + if(a==null){ + return null; + } + else{ + int n = a.length; + int m = a[0].length; + int l = a[0][0].length; + Complex[][][] b = Complex.threeDarray(n, m, l); + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + for(int k=0; k<l; k++){ + b[i][j][k]=Complex.copy(a[i][j][k]); + } + } + } + return b; + } + } + + // CLONE + // Overrides Java.Object method clone + // Copy a single complex number [instance method] + public Object clone(){ + Object ret = null; + + if(this!=null){ + Complex b = new Complex(); + b.real=this.real; + b.imag=this.imag; + ret = (Object)b; + } + + return ret; + } + + // ADDITION + // Add two Complex numbers [static method] + public static Complex plus(Complex a, Complex b){ + Complex c = new Complex(); + c.real=a.real+b.real; + c.imag=a.imag+b.imag; + return c; + } + + // Add a double to a Complex number [static method] + public static Complex plus(Complex a, double b){ + Complex c = new Complex(); + c.real=a.real+b; + c.imag=a.imag; + return c; + } + + // Add a Complex number to a double [static method] + public static Complex plus(double a, Complex b){ + Complex c = new Complex(); + c.real=a+b.real; + c.imag=b.imag; + return c; + } + + // Add a double number to a double and return sum as Complex [static method] + public static Complex plus(double a, double b){ + Complex c = new Complex(); + c.real=a+b; + c.imag=0.0D; + return c; + } + + // Add a Complex number to this Complex number [instance method] + // this Complex number remains unaltered + public Complex plus(Complex a ){ + Complex b = new Complex(); + b.real=this.real + a.real; + b.imag=this.imag + a.imag; + return b; + } + + // Add double number to this Complex number [instance method] + // this Complex number remains unaltered + public Complex plus(double a ){ + Complex b = new Complex(); + b.real = this.real + a; + b.imag = this.imag; + return b; + } + + // Add a Complex number to this Complex number and replace this with the sum + public void plusEquals(Complex a ){ + this.real+=a.real; + this.imag+=a.imag; + } + + // Add double number to this Complex number and replace this with the sum + public void plusEquals(double a ){ + this.real+=a; + this.imag=this.imag; + } + + // SUBTRACTION + // Subtract two Complex numbers [static method] + public static Complex minus (Complex a, Complex b){ + Complex c = new Complex(); + c.real=a.real-b.real; + c.imag=a.imag-b.imag; + return c; + } + + // Subtract a double from a Complex number [static method] + public static Complex minus(Complex a, double b){ + Complex c = new Complex(); + c.real=a.real-b; + c.imag=a.imag; + return c; + } + + // Subtract a Complex number from a double [static method] + public static Complex minus(double a, Complex b){ + Complex c = new Complex(); + c.real=a-b.real; + c.imag=-b.imag; + return c; + } + + // Subtract a double number to a double and return difference as Complex [static method] + public static Complex minus(double a, double b){ + Complex c = new Complex(); + c.real=a-b; + c.imag=0.0D; + return c; + } + + // Subtract a Complex number from this Complex number [instance method] + // this Complex number remains unaltered + public Complex minus(Complex a ){ + Complex b = new Complex(); + b.real=this.real-a.real; + b.imag=this.imag-a.imag; + return b; + } + + // Subtract a double number from this Complex number [instance method] + // this Complex number remains unaltered + public Complex minus(double a ){ + Complex b = new Complex(); + b.real=this.real-a; + b.imag=this.imag; + return b; + } + + // Subtract this Complex number from a double number [instance method] + // this Complex number remains unaltered + public Complex transposedMinus(double a ){ + Complex b = new Complex(); + b.real=a - this.real; + b.imag=this.imag; + return b; + } + + // Subtract a Complex number from this Complex number and replace this by the difference + public void minusEquals(Complex a ){ + this.real-=a.real; + this.imag-=a.imag; + } + + // Subtract a double number from this Complex number and replace this by the difference + public void minusEquals(double a ){ + this.real-=a; + this.imag=this.imag; + } + + // MULTIPLICATION + // Sets the infinity handling option in multiplication and division + // infOption -> true; standard arithmetic overriden - see above (instance variable definitions) for details + // infOption -> false: standard arithmetic used + public static void setInfOption(boolean infOpt){ + Complex.infOption = infOpt; + } + + // Sets the infinity handling option in multiplication and division + // opt = 0: infOption -> true; standard arithmetic overriden - see above (instance variable definitions) for details + // opt = 1: infOption -> false: standard arithmetic used + public static void setInfOption(int opt){ + if(opt<0 || opt>1)throw new IllegalArgumentException("opt must be 0 or 1"); + Complex.infOption = true; + if(opt==1)Complex.infOption = false; + } + + // Gets the infinity handling option in multiplication and division + // infOption -> true; standard arithmetic overriden - see above (instance variable definitions) for details + // infOption -> false: standard arithmetic used + public static boolean getInfOption(){ + return Complex.infOption; + } + + // Multiply two Complex numbers [static method] + public static Complex times(Complex a, Complex b){ + Complex c = new Complex(0.0D, 0.0D); + if(Complex.infOption){ + if(a.isInfinite() && !b.isZero()){ + c.reset(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + return c; + } + if(b.isInfinite() && !a.isZero()){ + c.reset(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + return c; + } + } + + c.real=a.real*b.real-a.imag*b.imag; + c.imag=a.real*b.imag+a.imag*b.real; + return c; + } + + // Multiply a Complex number by a double [static method] + public static Complex times(Complex a, double b){ + Complex c = new Complex(); + if(Complex.infOption){ + if(a.isInfinite() && b!=0.0D){ + c.reset(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + return c; + } + if(Fmath.isInfinity(b) && !a.isZero()){ + c.reset(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + return c; + } + } + c.real=a.real*b; + c.imag=a.imag*b; + return c; + } + + // Multiply a double by a Complex number [static method] + public static Complex times(double a, Complex b){ + Complex c = new Complex(); + if(Complex.infOption){ + if(b.isInfinite() && a!=0.0D){ + c.reset(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + return c; + } + if(Fmath.isInfinity(a) && !b.isZero()){ + c.reset(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + return c; + } + } + + c.real=a*b.real; + c.imag=a*b.imag; + return c; + } + + // Multiply a double number to a double and return product as Complex [static method] + public static Complex times(double a, double b){ + Complex c = new Complex(); + c.real=a*b; + c.imag=0.0D; + return c; + } + + // Multiply this Complex number by a Complex number [instance method] + // this Complex number remains unaltered + public Complex times(Complex a){ + Complex b = new Complex(); + if(Complex.infOption){ + if(this.isInfinite() && !a.isZero()){ + b.reset(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + return b; + } + if(a.isInfinite() && !this.isZero()){ + b.reset(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + return b; + } + } + + b.real=this.real*a.real-this.imag*a.imag; + b.imag=this.real*a.imag+this.imag*a.real; + return b; + } + + // Multiply this Complex number by a double [instance method] + // this Complex number remains unaltered + public Complex times(double a){ + Complex b = new Complex(); + if(Complex.infOption){ + if(this.isInfinite() && a!=0.0D){ + b.reset(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + return b; + } + if(Fmath.isInfinity(a) && !this.isZero()){ + b.reset(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + return b; + } + } + + b.real=this.real*a; + b.imag=this.imag*a; + return b; + } + + // Multiply this Complex number by a Complex number and replace this by the product + public void timesEquals(Complex a){ + Complex b = new Complex(); + boolean test = true; + if(Complex.infOption){ + if((this.isInfinite() && !a.isZero()) || (a.isInfinite() && !this.isZero())){ + this.real = Double.POSITIVE_INFINITY; + this.imag = Double.POSITIVE_INFINITY; + test = false; + } + } + if(test){ + b.real=a.real*this.real-a.imag*this.imag; + b.imag=a.real*this.imag+a.imag*this.real; + this.real=b.real; + this.imag=b.imag; + } + } + + // Multiply this Complex number by a double and replace this by the product + public void timesEquals(double a){ + boolean test = true; + if(Complex.infOption){ + if((this.isInfinite() && a!=0.0D) || (Fmath.isInfinity(a) && !this.isZero())){ + this.real = Double.POSITIVE_INFINITY; + this.imag = Double.POSITIVE_INFINITY; + test = false; + } + } + if(test){ + this.real=this.real*a; + this.imag=this.imag*a; + } + } + + + // DIVISION + // Division of two Complex numbers a/b [static method] + public static Complex over(Complex a, Complex b){ + Complex c = new Complex(0.0D,0.0D); + if(Complex.infOption && !a.isInfinite() && b.isInfinite())return c; + + double denom = 0.0D, ratio = 0.0D; + if(a.isZero()){ + if(b.isZero()){ + c.real=Double.NaN; + c.imag=Double.NaN; + } + else{ + c.real=0.0D; + c.imag=0.0D; + } + } + else{ + if(Math.abs(b.real)>=Math.abs(b.imag)){ + ratio=b.imag/b.real; + denom=b.real+b.imag*ratio; + c.real=(a.real+a.imag*ratio)/denom; + c.imag=(a.imag-a.real*ratio)/denom; + } + else{ + ratio=b.real/b.imag; + denom=b.real*ratio+b.imag; + c.real=(a.real*ratio+a.imag)/denom; + c.imag=(a.imag*ratio-a.real)/denom; + } + } + return c; + } + + // Division of a Complex number, a, by a double, b [static method] + public static Complex over(Complex a, double b){ + Complex c = new Complex(0.0D, 0.0D); + if(Complex.infOption && Fmath.isInfinity(b))return c; + + c.real=a.real/b; + c.imag=a.imag/b; + return c; + } + + // Division of a double, a, by a Complex number, b [static method] + public static Complex over(double a, Complex b){ + Complex c = new Complex(); + if(Complex.infOption && !Fmath.isInfinity(a) && b.isInfinite())return c; + + double denom, ratio; + + if(a==0.0D){ + if(b.isZero()){ + c.real=Double.NaN; + c.imag=Double.NaN; + } + else{ + c.real=0.0D; + c.imag=0.0D; + } + } + else{ + if(Math.abs(b.real)>=Math.abs(b.imag)){ + ratio=b.imag/b.real; + denom=b.real+b.imag*ratio; + c.real=a/denom; + c.imag=-a*ratio/denom; + } + else{ + ratio=b.real/b.imag; + denom=b.real*ratio+b.imag; + c.real=a*ratio/denom; + c.imag=-a/denom; + } + } + return c; + } + + // Divide a double number by a double and return quotient as Complex [static method] + public static Complex over(double a, double b){ + Complex c = new Complex(); + c.real=a/b; + c.imag=0.0; + return c; + } + + // Division of this Complex number by a Complex number [instance method] + // this Complex number remains unaltered + public Complex over(Complex a){ + Complex b = new Complex(0.0D, 0.0D); + if(Complex.infOption && !this.isInfinite() && a.isInfinite())return b; + + double denom = 0.0D, ratio = 0.0D; + if(Math.abs(a.real)>=Math.abs(a.imag)){ + ratio=a.imag/a.real; + denom=a.real+a.imag*ratio; + b.real=(this.real+this.imag*ratio)/denom; + b.imag=(this.imag-this.real*ratio)/denom; + } + else + { + ratio=a.real/a.imag; + denom=a.real*ratio+a.imag; + b.real=(this.real*ratio+this.imag)/denom; + b.imag=(this.imag*ratio-this.real)/denom; + } + return b; + } + + // Division of this Complex number by a double [instance method] + // this Complex number remains unaltered + public Complex over(double a){ + Complex b = new Complex(0.0D, 0.0D); + + b.real=this.real/a; + b.imag=this.imag/a; + return b; + } + + // Division of a double by this Complex number [instance method] + // this Complex number remains unaltered + public Complex transposedOver(double a){ + Complex c = new Complex(0.0D, 0.0D); + if(Complex.infOption && !Fmath.isInfinity(a) && this.isInfinite())return c; + + double denom = 0.0D, ratio = 0.0D; + if(Math.abs(this.real)>=Math.abs(this.imag)){ + ratio=this.imag/this.real; + denom=this.real+this.imag*ratio; + c.real=a/denom; + c.imag=-a*ratio/denom; + } + else + { + ratio=this.real/this.imag; + denom=this.real*ratio+this.imag; + c.real=a*ratio/denom; + c.imag=-a/denom; + } + return c; + } + + // Division of this Complex number by a Complex number and replace this by the quotient + public void overEquals(Complex b){ + Complex c = new Complex(0.0D, 0.0D); + + boolean test = true; + if(Complex.infOption && !this.isInfinite() && b.isInfinite()){ + this.real = 0.0D; + this.imag = 0.0D; + test=false; + } + if(test){ + double denom = 0.0D, ratio = 0.0D; + if(Math.abs(b.real)>=Math.abs(b.imag)){ + ratio=b.imag/b.real; + denom=b.real+b.imag*ratio; + c.real=(this.real+this.imag*ratio)/denom; + c.imag=(this.imag-this.real*ratio)/denom; + } + else + { + ratio=b.real/b.imag; + denom=b.real*ratio+b.imag; + c.real=(this.real*ratio+this.imag)/denom; + c.imag=(this.imag*ratio-this.real)/denom; + } + this.real = c.real; + this.imag = c.imag; + } + } + + // Division of this Complex number by a double and replace this by the quotient + public void overEquals(double a){ + this.real=this.real/a; + this.imag=this.imag/a; + } + + // RECIPROCAL + // Returns the reciprocal (1/a) of a Complex number (a) [static method] + public static Complex inverse(Complex a){ + Complex b = new Complex(0.0D, 0.0D); + if(Complex.infOption && a.isInfinite())return b; + + b = Complex.over(1.0D, a); + return b; + } + + // Returns the reciprocal (1/a) of a Complex number (a) [instance method] + public Complex inverse(){ + Complex b = new Complex(0.0D, 0.0D); + b = Complex.over(1.0D, this); + return b; + } + + // FURTHER MATHEMATICAL FUNCTIONS + + // Negates a Complex number [static method] + public static Complex negate(Complex a){ + Complex c = new Complex(); + c.real=-a.real; + c.imag=-a.imag; + return c; + } + + // Negates a Complex number [instance method] + public Complex negate(){ + Complex c = new Complex(); + c.real=-this.real; + c.imag=-this.imag; + return c; + } + + // Absolute value (modulus) of a complex number [static method] + public static double abs(Complex a){ + double rmod = Math.abs(a.real); + double imod = Math.abs(a.imag); + double ratio = 0.0D; + double res = 0.0D; + + if(rmod==0.0D){ + res=imod; + } + else{ + if(imod==0.0D){ + res=rmod; + } + if(rmod>=imod){ + ratio=a.imag/a.real; + res=rmod*Math.sqrt(1.0D + ratio*ratio); + } + else{ + ratio=a.real/a.imag; + res=imod*Math.sqrt(1.0D + ratio*ratio); + } + } + return res; + } + + // Absolute value (modulus) of a complex number [instance method] + public double abs(){ + double rmod = Math.abs(this.real); + double imod = Math.abs(this.imag); + double ratio = 0.0D; + double res = 0.0D; + + if(rmod==0.0D){ + res=imod; + } + else{ + if(imod==0.0D){ + res=rmod; + } + if(rmod>=imod){ + ratio=this.imag/this.real; + res=rmod*Math.sqrt(1.0D + ratio*ratio); + } + else + { + ratio=this.real/this.imag; + res=imod*Math.sqrt(1.0D + ratio*ratio); + } + } + return res; + } + + + // Square of the absolute value (modulus) of a complex number [static method] + public static double squareAbs(Complex a){ + return a.real*a.real + a.imag*a.imag; + } + + // Square of the absolute value (modulus) of a complex number [instance method] + public double squareAbs(){ + return this.real*this.real + this.imag*this.imag; + } + + // Argument of a complex number (in radians) [static method] + public static double arg(Complex a){ + return Math.atan2(a.imag, a.real); + } + + // Argument of a complex number (in radians)[instance method] + public double arg(){ + return Math.atan2(this.imag, this.real); + } + + // Argument of a complex number (in radians) [static method] + public static double argRad(Complex a){ + return Math.atan2(a.imag, a.real); + } + + // Argument of a complex number (in radians)[instance method] + public double argRad(){ + return Math.atan2(this.imag, this.real); + } + + // Argument of a complex number (in degrees) [static method] + public static double argDeg(Complex a){ + return Math.toDegrees(Math.atan2(a.imag, a.real)); + } + + // Argument of a complex number (in degrees)[instance method] + public double argDeg(){ + return Math.toDegrees(Math.atan2(this.imag, this.real)); + } + + // Complex conjugate of a complex number [static method] + public static Complex conjugate(Complex a){ + Complex c = new Complex(); + c.real=a.real; + c.imag=-a.imag; + return c; + } + + // Complex conjugate of a complex number [instance method] + public Complex conjugate(){ + Complex c = new Complex(); + c.real=this.real; + c.imag=-this.imag; + return c; + } + + // Returns the length of the hypotenuse of a and b i.e. sqrt(abs(a)*abs(a)+abs(b)*abs(b)) + // where a and b are Complex [without unecessary overflow or underflow] + public static double hypot(Complex aa, Complex bb){ + double amod=Complex.abs(aa); + double bmod=Complex.abs(bb); + double cc = 0.0D, ratio = 0.0D; + + if(amod==0.0D){ + cc=bmod; + } + else{ + if(bmod==0.0D){ + cc=amod; + } + else{ + if(amod>=bmod){ + ratio=bmod/amod; + cc=amod*Math.sqrt(1.0 + ratio*ratio); + } + else{ + ratio=amod/bmod; + cc=bmod*Math.sqrt(1.0 + ratio*ratio); + } + } + } + return cc; + } + + // Exponential of a complex number (instance method) + public Complex exp(){ + return Complex.exp(this); + } + + // Exponential of a complex number (static method) + public static Complex exp(Complex aa){ + Complex z = new Complex(); + + double a = aa.real; + double b = aa.imag; + + if(b==0.0D){ + z.real=Math.exp(a); + z.imag=0.0D; + } + else{ + if(a==0D){ + z.real=Math.cos(b); + z.imag=Math.sin(b); + } + else{ + double c=Math.exp(a); + z.real=c*Math.cos(b); + z.imag=c*Math.sin(b); + } + } + return z; + } + + // Exponential of a real number returned as a complex number + public static Complex exp(double aa){ + Complex bb = new Complex(aa, 0.0D); + return Complex.exp(bb); + } + + // Returns exp(j*arg) where arg is real (a double) + public static Complex expPlusJayArg(double arg){ + Complex argc = new Complex(0.0D, arg); + return Complex.exp(argc); + } + + // Returns exp(-j*arg) where arg is real (a double) + public static Complex expMinusJayArg(double arg){ + Complex argc = new Complex(0.0D, -arg); + return Complex.exp(argc); + } + + // Principal value of the natural log of an Complex number (instance method) + public Complex log(){ + + double a=this.real; + double b=this.imag; + Complex c = new Complex(); + + c.real=Math.log(Complex.abs(this)); + c.imag=Math.atan2(b,a); + + return c; + } + + // Principal value of the natural log of an Complex number + public static Complex log(Complex aa ){ + + double a=aa.real; + double b=aa.imag; + Complex c = new Complex(); + + c.real=Math.log(Complex.abs(aa)); + c.imag=Math.atan2(b,a); + + return c; + } + + // Roots + // Principal value of the square root of a complex number (instance method) + public Complex sqrt(){ + return Complex.sqrt(this); + } + + + // Principal value of the square root of a complex number + public static Complex sqrt(Complex aa ){ + double a=aa.real; + double b=aa.imag; + Complex c = new Complex(); + + if(b==0.0D){ + if(a>=0.0D){ + c.real=Math.sqrt(a); + c.imag=0.0D; + } + else{ + c.real=0.0D; + c.imag= Math.sqrt(-a); + } + } + else{ + double w, ratio; + double amod=Math.abs(a); + double bmod=Math.abs(b); + if(amod>=bmod){ + ratio=b/a; + w=Math.sqrt(amod)*Math.sqrt(0.5D*(1.0D + Math.sqrt(1.0D + ratio*ratio))); + } + else{ + ratio=a/b; + w=Math.sqrt(bmod)*Math.sqrt(0.5D*(Math.abs(ratio) + Math.sqrt(1.0D + ratio*ratio))); + } + if(a>=0.0){ + c.real=w; + c.imag=b/(2.0D*w); + } + else{ + if(b>=0.0){ + c.imag=w; + c.real=b/(2.0D*c.imag); + } + else{ + c.imag=-w; + c.real=b/(2.0D*c.imag); + } + } + } + return c; + } + + // Principal value of the nth root of a complex number (n = integer > 1) [instance method] + public Complex nthRoot(int n){ + return Complex.nthRoot(this, n); + } + + + // Principal value of the nth root of a complex number (n = integer > 1) [static method] + public static Complex nthRoot(Complex aa, int n ){ + Complex c = new Complex(); + if(n==0){ + c = new Complex(Double.POSITIVE_INFINITY, 0.0); + } + else{ + if(n==1){ + c = aa; + } + else{ + c = Complex.exp((Complex.log(aa)).over((double)n)); + } + } + + return c; + } + + // Powers + // Square of a complex number (static method) + public static Complex square(Complex aa){ + Complex c = new Complex(); + c.real= aa.real*aa.real-aa.imag*aa.imag; + c.imag= 2.0D*aa.real*aa.imag; + return c; + } + + // Square of a complex number (instance method) + public Complex square(){ + return this.times(this); + } + + // returns a Complex number raised to a Complex power (instance method) + public Complex pow(Complex b ){ + Complex c = new Complex(); + if(this.isZero()){ + if(b.imag==0){ + if(b.real==0){ + c = new Complex(1.0, 0.0); + } + else{ + if(b.real>0.0){ + c = new Complex(0.0, 0.0); + } + else{ + if(b.real<0.0){ + c = new Complex(Double.POSITIVE_INFINITY, 0.0); + } + } + } + } + else{ + c = Complex.exp(b.times(Complex.log(this))); + } + } + else{ + c = Complex.exp(b.times(Complex.log(this))); + } + + return c; + } + + // returns a Complex number raised to a Complex power + public static Complex pow(Complex a, Complex b ){ + Complex c = new Complex(); + if(a.isZero()){ + if(b.imag==0){ + if(b.real==0){ + c = new Complex(1.0, 0.0); + } + else{ + if(a.real>0.0){ + c = new Complex(0.0, 0.0); + } + else{ + if(a.real<0.0){ + c = new Complex(Double.POSITIVE_INFINITY, 0.0); + } + } + } + } + else{ + c=Complex.exp(b.times(Complex.log(a))); + } + } + else{ + c=Complex.exp(b.times(Complex.log(a))); + } + + return c; + } + + // returns a Complex number raised to a double power [instance method] + public Complex pow(double b){ + return powDouble(this, b); + } + + // returns a Complex number raised to a double power + public static Complex pow(Complex a, double b){ + return powDouble(a, b); + } + + // returns a Complex number raised to an integer, i.e. int, power [instance method] + public Complex pow(int n ){ + double b = (double) n; + return powDouble(this, b); + } + + // returns a Complex number raised to an integer, i.e. int, power + public static Complex pow(Complex a, int n ){ + double b = (double) n; + return powDouble(a, b); + } + + // returns a double raised to a Complex power + public static Complex pow(double a, Complex b ){ + Complex c = new Complex(); + if(a==0){ + if(b.imag==0){ + if(b.real==0){ + c = new Complex(1.0, 0.0); + } + else{ + if(b.real>0.0){ + c = new Complex(0.0, 0.0); + } + else{ + if(b.real<0.0){ + c = new Complex(Double.POSITIVE_INFINITY, 0.0); + } + } + } + } + else{ + double z = Math.pow(a, b.real); + c=Complex.exp(Complex.times(Complex.plusJay(), b.imag*Math.log(a))); + c=Complex.times(z, c); + } + } + else{ + double z = Math.pow(a, b.real); + c=Complex.exp(Complex.times(Complex.plusJay(), b.imag*Math.log(a))); + c=Complex.times(z, c); + } + + return c; + + } + + // Complex trigonometric functions + + // Sine of an Complex number + public Complex sin(){ + return Complex.sin(this); + } + + public static Complex sin(Complex aa ){ + Complex c = new Complex(); + double a = aa.real; + double b = aa.imag; + c.real = Math.sin(a)*Fmath.cosh(b); + c.imag = Math.cos(a)*Fmath.sinh(b); + return c; + } + + // Cosine of an Complex number + public Complex cos(){ + return Complex.cos(this); + } + + public static Complex cos(Complex aa ){ + Complex c = new Complex(); + double a = aa.real; + double b = aa.imag; + c.real= Math.cos(a)*Fmath.cosh(b); + c.imag= -Math.sin(a)*Fmath.sinh(b); + return c; + } + + // Secant of an Complex number + public Complex sec(){ + return Complex.sec(this); + } + + public static Complex sec(Complex aa ){ + Complex c = new Complex(); + double a = aa.real; + double b = aa.imag; + c.real= Math.cos(a)*Fmath.cosh(b); + c.imag= -Math.sin(a)*Fmath.sinh(b); + return c.inverse(); + } + + // Cosecant of an Complex number + public Complex csc(){ + return Complex.csc(this); + } + + public static Complex csc(Complex aa ){ + Complex c = new Complex(); + double a = aa.real; + double b = aa.imag; + c.real = Math.sin(a)*Fmath.cosh(b); + c.imag = Math.cos(a)*Fmath.sinh(b); + return c.inverse(); + } + + // Tangent of an Complex number + public Complex tan(){ + return Complex.tan(this); + } + + public static Complex tan(Complex aa ){ + Complex c = new Complex(); + double denom = 0.0D; + double a = aa.real; + double b = aa.imag; + + Complex x = new Complex(Math.sin(a)*Fmath.cosh(b), Math.cos(a)*Fmath.sinh(b)); + Complex y = new Complex(Math.cos(a)*Fmath.cosh(b), -Math.sin(a)*Fmath.sinh(b)); + c=Complex.over(x, y); + return c; + } + + // Cotangent of an Complex number + public Complex cot(){ + return Complex.cot(this); + } + + public static Complex cot(Complex aa ){ + Complex c = new Complex(); + double denom = 0.0D; + double a = aa.real; + double b = aa.imag; + + Complex x = new Complex(Math.sin(a)*Fmath.cosh(b), Math.cos(a)*Fmath.sinh(b)); + Complex y = new Complex(Math.cos(a)*Fmath.cosh(b), -Math.sin(a)*Fmath.sinh(b)); + c=Complex.over(y, x); + return c; + } + + // Exsecant of an Complex number + public Complex exsec(){ + return Complex.exsec(this); + } + + public static Complex exsec(Complex aa ){ + return Complex.sec(aa).minus(1.0D); + } + + // Versine of an Complex number + public Complex vers(){ + return Complex.vers(this); + } + + public static Complex vers(Complex aa ){ + return Complex.plusOne().minus(Complex.cos(aa)); + } + + // Coversine of an Complex number + public Complex covers(){ + return Complex.covers(this); + } + + public static Complex covers(Complex aa ){ + return Complex.plusOne().minus(Complex.sin(aa)); + } + + // Haversine of an Complex number + public Complex hav(){ + return Complex.hav(this); + } + + public static Complex hav(Complex aa ){ + return Complex.vers(aa).over(2.0D); + } + + // Hyperbolic sine of a Complex number + public Complex sinh(){ + return Complex.sinh(this); + } + + public static Complex sinh(Complex a ){ + Complex c = new Complex(); + c=a.times(plusJay()); + c=(Complex.minusJay()).times(Complex.sin(c)); + return c; + } + + // Hyperbolic cosine of a Complex number + public Complex cosh(){ + return Complex.cosh(this); + } + + public static Complex cosh(Complex a ){ + Complex c = new Complex(); + c=a.times(Complex.plusJay()); + c=Complex.cos(c); + return c; + } + + // Hyperbolic tangent of a Complex number + public Complex tanh(){ + return Complex.tanh(this); + } + + public static Complex tanh(Complex a ){ + Complex c = new Complex(); + c = (Complex.sinh(a)).over(Complex.cosh(a)); + return c; + } + + // Hyperbolic cotangent of a Complex number + public Complex coth(){ + return Complex.coth(this); + } + + public static Complex coth(Complex a ){ + Complex c = new Complex(); + c = (Complex.cosh(a)).over(Complex.sinh(a)); + return c; + } + + // Hyperbolic secant of a Complex number + public Complex sech(){ + return Complex.sech(this); + } + + public static Complex sech(Complex a ){ + Complex c = new Complex(); + c = (Complex.cosh(a)).inverse(); + return c; + } + + // Hyperbolic cosecant of a Complex number + public Complex csch(){ + return Complex.csch(this); + } + + public static Complex csch(Complex a ){ + Complex c = new Complex(); + c = (Complex.sinh(a)).inverse(); + return c; + } + + + // Inverse sine of a Complex number + public Complex asin(){ + return Complex.asin(this); + } + + public static Complex asin(Complex a ){ + Complex c = new Complex(); + c=Complex.sqrt(Complex.minus(1.0D, Complex.square(a))); + c=(Complex.plusJay().times(a)).plus(c); + c=Complex.minusJay().times(Complex.log(c)); + return c; + } + + // Inverse cosine of a Complex number + public Complex acos(){ + return Complex.acos(this); + } + + public static Complex acos(Complex a ){ + Complex c = new Complex(); + c=Complex.sqrt(Complex.minus(Complex.square(a),1.0)); + c=a.plus(c); + c=Complex.minusJay().times(Complex.log(c)); + return c; + } + + // Inverse tangent of a Complex number + public Complex atan(){ + return Complex.atan(this); + } + + public static Complex atan(Complex a ){ + Complex c = new Complex(); + Complex d = new Complex(); + + c=Complex.plusJay().plus(a); + d=Complex.plusJay().minus(a); + c=c.over(d); + c=Complex.log(c); + c=Complex.plusJay().times(c); + c=c.over(2.0D); + return c; + } + + // Inverse cotangent of a Complex number + public Complex acot(){ + return Complex.acot(this); + } + + public static Complex acot(Complex a ){ + return Complex.atan(a.inverse()); + } + + // Inverse secant of a Complex number + public Complex asec(){ + return Complex.asec(this); + } + + public static Complex asec(Complex a ){ + return Complex.acos(a.inverse()); + } + + // Inverse cosecant of a Complex number + public Complex acsc(){ + return Complex.acsc(this); + } + + public static Complex acsc(Complex a ){ + return Complex.asin(a.inverse()); + } + + // Inverse exsecant of a Complex number + public Complex aexsec(){ + return Complex.aexsec(this); + } + + public static Complex aexsec(Complex a ){ + Complex c = a.plus(1.0D); + return Complex.asin(c.inverse()); + } + + // Inverse versine of a Complex number + public Complex avers(){ + return Complex.avers(this); + } + + public static Complex avers(Complex a ){ + Complex c = Complex.plusOne().plus(a); + return Complex.acos(c); + } + + // Inverse coversine of a Complex number + public Complex acovers(){ + return Complex.acovers(this); + } + + public static Complex acovers(Complex a ){ + Complex c = Complex.plusOne().plus(a); + return Complex.asin(c); + } + + // Inverse haversine of a Complex number + public Complex ahav(){ + return Complex.ahav(this); + } + + public static Complex ahav(Complex a ){ + Complex c = Complex.plusOne().minus(a.times(2.0D)); + return Complex.acos(c); + } + + // Inverse hyperbolic sine of a Complex number + public Complex asinh(){ + return Complex.asinh(this); + } + + public static Complex asinh(Complex a ){ + Complex c = new Complex(0.0D, 0.0D); + c=Complex.sqrt(Complex.square(a).plus(1.0D)); + c=a.plus(c); + c=Complex.log(c); + + return c; + } + + // Inverse hyperbolic cosine of a Complex number + public Complex acosh(){ + return Complex.acosh(this); + } + + public static Complex acosh(Complex a ){ + Complex c = new Complex(); + c=Complex.sqrt(Complex.square(a).minus(1.0D)); + c=a.plus(c); + c=Complex.log(c); + return c; + } + + // Inverse hyperbolic tangent of a Complex number + public Complex atanh(){ + return Complex.atanh(this); + } + + public static Complex atanh(Complex a ){ + Complex c = new Complex(); + Complex d = new Complex(); + c=Complex.plusOne().plus(a); + d=Complex.plusOne().minus(a); + c=c.over(d); + c=Complex.log(c); + c=c.over(2.0D); + return c; + } + + // Inverse hyperbolic cotangent of a Complex number + public Complex acoth(){ + return Complex.acoth(this); + } + + public static Complex acoth(Complex a ){ + Complex c = new Complex(); + Complex d = new Complex(); + c=Complex.plusOne().plus(a); + d=a.plus(1.0D); + c=c.over(d); + c=Complex.log(c); + c=c.over(2.0D); + return c; + } + + // Inverse hyperbolic secant of a Complex number + public Complex asech(){ + return Complex.asech(this); + } + + public static Complex asech(Complex a ){ + Complex c = a.inverse(); + Complex d = (Complex.square(a)).minus(1.0D); + return Complex.log(c.plus(Complex.sqrt(d))); + } + + // Inverse hyperbolic cosecant of a Complex number + public Complex acsch(){ + return Complex.acsch(this); + } + + public static Complex acsch(Complex a ){ + Complex c = a.inverse(); + Complex d = (Complex.square(a)).plus(1.0D); + return Complex.log(c.plus(Complex.sqrt(d))); + } + + + + + // LOGICAL FUNCTIONS + // Returns true if the Complex number has a zero imaginary part, i.e. is a real number + public static boolean isReal(Complex a){ + boolean test = false; + if(a.imag==0.0D)test = true; + return test; + } + + public boolean isReal(){ + boolean test = false; + if(Math.abs(this.imag)==0.0D)test = true; + return test; + } + + // Returns true if the Complex number has a zero real and a zero imaginary part + // i.e. has a zero modulus + public static boolean isZero(Complex a){ + boolean test = false; + if(Math.abs(a.real)==0.0D && Math.abs(a.imag)==0.0D)test = true; + return test; + } + + public boolean isZero(){ + boolean test = false; + if(Math.abs(this.real)==0.0D && Math.abs(this.imag)==0.0D)test = true; + return test; + } + + // Returns true if either the real or the imaginary part of the Complex number + // is equal to plus infinity + public boolean isPlusInfinity(){ + boolean test = false; + if(this.real==Double.POSITIVE_INFINITY || this.imag==Double.POSITIVE_INFINITY)test = true; + return test; + } + + public static boolean isPlusInfinity(Complex a){ + boolean test = false; + if(a.real==Double.POSITIVE_INFINITY || a.imag==Double.POSITIVE_INFINITY)test = true; + return test; + } + + // Returns true if either the real or the imaginary part of the Complex number + // is equal to minus infinity + public boolean isMinusInfinity(){ + boolean test = false; + if(this.real==Double.NEGATIVE_INFINITY || this.imag==Double.NEGATIVE_INFINITY)test = true; + return test; + } + + public static boolean isMinusInfinity(Complex a){ + boolean test = false; + if(a.real==Double.NEGATIVE_INFINITY || a.imag==Double.NEGATIVE_INFINITY)test = true; + return test; + } + + + // Returns true if either the real or the imaginary part of the Complex number + // is equal to either infinity or minus plus infinity + public static boolean isInfinite(Complex a){ + boolean test = false; + if(a.real==Double.POSITIVE_INFINITY || a.imag==Double.POSITIVE_INFINITY)test = true; + if(a.real==Double.NEGATIVE_INFINITY || a.imag==Double.NEGATIVE_INFINITY)test = true; + return test; + } + + public boolean isInfinite(){ + boolean test = false; + if(this.real==Double.POSITIVE_INFINITY || this.imag==Double.POSITIVE_INFINITY)test = true; + if(this.real==Double.NEGATIVE_INFINITY || this.imag==Double.NEGATIVE_INFINITY)test = true; + return test; + } + + // Returns true if the Complex number is NaN (Not a Number) + // i.e. is the result of an uninterpretable mathematical operation + public static boolean isNaN(Complex a){ + boolean test = false; + if(a.real!=a.real || a.imag!=a.imag)test = true; + return test; + } + + public boolean isNaN(){ + boolean test = false; + if(this.real!=this.real || this.imag!=this.imag)test = true; + return test; + } + + // Returns true if two Complex number are identical + // Follows the Sun Java convention of treating all NaNs as equal + // i.e. does not satisfies the IEEE 754 specification + // but does let hashtables operate properly + public boolean equals(Complex a){ + boolean test = false; + if(this.isNaN()&&a.isNaN()){ + test=true; + } + else{ + if(this.real == a.real && this.imag == a.imag)test = true; + } + return test; + } + + public boolean isEqual(Complex a){ + boolean test = false; + if(this.isNaN()&&a.isNaN()){ + test=true; + } + else{ + if(this.real == a.real && this.imag == a.imag)test = true; + } + return test; + } + + + public static boolean isEqual(Complex a, Complex b){ + boolean test = false; + if(isNaN(a)&&isNaN(b)){ + test=true; + } + else{ + if(a.real == b.real && a.imag == b.imag)test = true; + } + return test; + } + + + + // returns true if the differences between the real and imaginary parts of two complex numbers + // are less than fract times the larger real and imaginary part + public boolean equalsWithinLimits(Complex a, double fract){ + return isEqualWithinLimits(a, fract); + } + + public boolean isEqualWithinLimits(Complex a, double fract){ + boolean test = false; + + double rt = this.getReal(); + double ra = a.getReal(); + double it = this.getImag(); + double ia = a.getImag(); + double rdn = 0.0D; + double idn = 0.0D; + double rtest = 0.0D; + double itest = 0.0D; + + if(rt==0.0D && it==0.0D && ra==0.0D && ia==0.0D)test=true; + if(!test){ + rdn=Math.abs(rt); + if(Math.abs(ra)>rdn)rdn=Math.abs(ra); + if(rdn==0.0D){ + rtest=0.0; + } + else{ + rtest=Math.abs(ra-rt)/rdn; + } + idn=Math.abs(it); + if(Math.abs(ia)>idn)idn=Math.abs(ia); + if(idn==0.0D){ + itest=0.0; + } + else{ + itest=Math.abs(ia-it)/idn; + } + if(rtest<fract && itest<fract)test=true; + } + + return test; + } + + public static boolean isEqualWithinLimits(Complex a, Complex b, double fract){ + boolean test = false; + + double rb = b.getReal(); + double ra = a.getReal(); + double ib = b.getImag(); + double ia = a.getImag(); + double rdn = 0.0D; + double idn = 0.0D; + + if(ra==0.0D && ia==0.0D && rb==0.0D && ib==0.0D)test=true; + if(!test){ + rdn=Math.abs(rb); + if(Math.abs(ra)>rdn)rdn=Math.abs(ra); + idn=Math.abs(ib); + if(Math.abs(ia)>idn)idn=Math.abs(ia); + if(Math.abs(ra-rb)/rdn<fract && Math.abs(ia-ia)/idn<fract)test=true; + } + + return test; + } + + // SOME USEFUL NUMBERS + // returns the number zero (0) as a complex number + public static Complex zero(){ + Complex c = new Complex(); + c.real=0.0D; + c.imag=0.0D; + return c; + } + + // returns the number one (+1) as a complex number + public static Complex plusOne(){ + Complex c = new Complex(); + c.real=1.0D; + c.imag=0.0D; + return c; + } + + // returns the number minus one (-1) as a complex number + public static Complex minusOne(){ + Complex c = new Complex(); + c.real=-1.0D; + c.imag=0.0D; + return c; + } + + // returns plus j + public static Complex plusJay(){ + Complex c = new Complex(); + c.real=0.0D; + c.imag=1.0D; + return c; + } + + // returns minus j + public static Complex minusJay(){ + Complex c = new Complex(); + c.real=0.0D; + c.imag=-1.0D; + return c; + } + + // returns pi as a Complex number + public static Complex pi(){ + Complex c = new Complex(); + c.real=Math.PI; + c.imag=0.0D; + return c; + } + + // returns 2.pi.j + public static Complex twoPiJay(){ + Complex c = new Complex(); + c.real=0.0D; + c.imag=2.0D*Math.PI; + return c; + } + + // infinity + infinity.j + public static Complex plusInfinity(){ + Complex c = new Complex(); + c.real=Double.POSITIVE_INFINITY; + c.imag=Double.POSITIVE_INFINITY; + return c; + } + + // -infinity - infinity.j + public static Complex minusInfinity(){ + Complex c = new Complex(); + c.real=Double.NEGATIVE_INFINITY; + c.imag=Double.NEGATIVE_INFINITY; + return c; + } + + // PRIVATE METHODS + // returns a Complex number raised to a double power + // this method is used for calculation within this class file + // see above for corresponding public method + private static Complex powDouble(Complex a, double b){ + Complex z = new Complex(); + double re=a.real; + double im=a.imag; + + if(a.isZero()){ + if(b==0.0){ + z = new Complex(1.0, 0.0); + } + else{ + if(b>0.0){ + z = new Complex(0.0, 0.0); + } + else{ + if(b<0.0){ + z = new Complex(Double.POSITIVE_INFINITY, 0.0); + } + } + } + } + else{ + if(im==0.0D && re>0.0D){ + z.real=Math.pow(re, b); + z.imag=0.0D; + } + else{ + if(re==0.0D){ + z=Complex.exp(Complex.times(b, Complex.log(a))); + } + else{ + double c=Math.pow(re*re+im*im, b/2.0D); + double th=Math.atan2(im, re); + z.real=c*Math.cos(b*th); + z.imag=c*Math.sin(b*th); + } + } + } + return z; + } + +} diff --git a/src/main/java/flanagan/complex/ComplexErrorProp.java b/src/main/java/flanagan/complex/ComplexErrorProp.java new file mode 100755 index 0000000000000000000000000000000000000000..75b189b2bb44674fb9a51dfe103cfda7d54ecb29 --- /dev/null +++ b/src/main/java/flanagan/complex/ComplexErrorProp.java @@ -0,0 +1,718 @@ +/* +* Class ComplexErrorProp +* +* Defines an object describing a complex number in which there are +* errors associted with real and imaginary parts aqnd includes the +* methods for propagating the error in standard arithmetic operations +* for both uncorrelated errors only. +* +* AUTHOR: Dr Michael Thomas Flanagan +* +* DATE: 27 April 2004 +* UPDATE: 19 January 2005, 28 May 2007 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ComplexErrorProp.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) April 2004, May 2007 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ucl.ee.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.complex; + +import flanagan.math.*; +import flanagan.analysis.*; + +public class ComplexErrorProp{ + + private ErrorProp eReal = new ErrorProp(); // Real part of a complex number + private ErrorProp eImag = new ErrorProp(); // Imaginary part of a complex number + private double corrCoeff = 0.0D; // correlation coefficient between real and imaginary parts + private static int monteCarloLength = 10000;// length of Monte Carlo simulation arrays + +/*********************************************************/ + + // CONSTRUCTORS + // default constructor - value and error of real and imag = zero + // no correlation between real and imaginary parts + public ComplexErrorProp() + { + this.eReal.reset(0.0D, 0.0D); + this.eImag.reset(0.0D, 0.0D); + this.corrCoeff = 0.0D; + } + + // constructor - initialises both real and imag with ErrorProp - no correlation between real and imaginary parts + public ComplexErrorProp(ErrorProp eReal, ErrorProp eImag) + { + this.eReal = eReal.copy(); + this.eImag = eImag.copy(); + this.corrCoeff = 0.0D; + } + // constructor - initialises both real and imag with ErrorProp with correlation between real and imaginary parts + public ComplexErrorProp(ErrorProp eReal, ErrorProp eImag, double corrCoeff) + { + this.eReal = eReal.copy(); + this.eImag = eImag.copy(); + this.corrCoeff = corrCoeff; + } + + // constructor - initialises both real and imag with doubles - no correlation between real and imaginary parts + public ComplexErrorProp(double eRealValue, double eRealError, double eImagValue, double eImagError) + { + this.eReal.reset(eRealValue, eRealError); + this.eImag.reset(eImagValue, eImagError); + this.corrCoeff = 0.0D; + } + + // constructor - initialises both real and imag with doubles with correlation between real and imaginary parts + public ComplexErrorProp(double eRealValue, double eRealError, double eImagValue, double eImagError, double corrCoeff) + { + this.eReal.reset(eRealValue, eRealError); + this.eImag.reset(eImagValue, eImagError); + this.corrCoeff = corrCoeff; + } + +/*********************************************************/ + + // PUBLIC METHODS + + // SET VALUES + // Set the values of real and imag - no correlation between real and imaginary + public void reset(ErrorProp eReal, ErrorProp eImag){ + this.eReal = eReal.copy(); + this.eImag = eImag.copy(); + this.corrCoeff = 0.0D; + } + + // Set the values of real and imag with correlation between real and imaginary + public void reset(ErrorProp eReal, ErrorProp eImag, double corrCoeff){ + this.eReal = eReal.copy(); + this.eImag = eImag.copy(); + this.corrCoeff = corrCoeff; + } + + // Set the values of real and imag - no correlation between real and imaginary + public void reset(double eRealValue, double eRealError, double eImagValue, double eImagError){ + this.eReal.setValue(eRealValue); + this.eReal.setError(eRealError); + this.eImag.setValue(eImagValue); + this.eImag.setError(eImagError); + this.corrCoeff = 0.0D; + } + + + // Set the values of real and imag with correlation between real and imaginary + public void reset(double eRealValue, double eRealError, double eImagValue, double eImagError, double corrCoeff){ + this.eReal.setValue(eRealValue); + this.eReal.setError(eRealError); + this.eImag.setValue(eImagValue); + this.eImag.setError(eImagError); + this.corrCoeff = corrCoeff; + } + + // Set the values of magnitude and phase - no correlation between real and imaginary parts + public void polar(ErrorProp eMag, ErrorProp ePhase){ + polar(eMag, ePhase, 0.0D); + } + + // Set the values of magnitude and phase with correlation between real and imaginary parts + public void polar(ErrorProp eMag, ErrorProp ePhase, double corrCoeff) + { + // calculate values and errors + ErrorProp a = new ErrorProp(); + a = eMag.times(ErrorProp.cos(ePhase), corrCoeff); + this.eReal = a; + a = eMag.times(ErrorProp.sin(ePhase), corrCoeff); + this.eImag = a; + + // calculate the new correlation coefficient + PsRandom rr = new PsRandom(); + double[][] ran = rr.correlatedGaussianArrays(eMag.getValue(), ePhase.getValue(), eMag.getError(), ePhase.getError(), corrCoeff, monteCarloLength); + + double[] rV = new double[monteCarloLength]; + double[] iV = new double[monteCarloLength]; + for(int i=0; i<monteCarloLength; i++){ + rV[i] = ran[0][i]*Math.cos(ran[1][i]); + iV[i] = ran[0][i]*Math.sin(ran[1][i]); + } + + this.corrCoeff = calcRho(rV, iV); + } + + /// calculates the correlation coefficient between x and y + public static double calcRho(double[] x, double[] y){ + int n = x.length; + if(n!=y.length)throw new IllegalArgumentException("length of x and y must be the same"); + + double meanX = 0.0D; + double meanY = 0.0D; + for(int i=0; i<n; i++){ + meanX += x[i]; + meanY += y[i]; + } + meanX /= n; + meanY /= n; + double varX = 0.0D; + double varY = 0.0D; + double covarXY = 0.0D; + for(int i=0; i<n; i++){ + varX+= Fmath.square(x[i]-meanX); + varY += Fmath.square(y[i]-meanY); + covarXY += (x[i]-meanX)*(y[i]-meanY); + } + varX = Math.sqrt(varX/(n-1)); + varY = Math.sqrt(varY/(n-1)); + covarXY = covarXY/(n-1); + + return covarXY/(varX*varY); + } + + // Set the values of magnitude and phase - no correlation between real and imaginary parts + public void polar(double eMagValue, double eMagError, double ePhaseValue, double ePhaseError){ + ErrorProp eMag = new ErrorProp(eMagValue, eMagError); + ErrorProp ePhase = new ErrorProp(ePhaseValue, ePhaseError); + polar(eMag, ePhase, 0.0D); + } + + // Set the values of magnitude and phase with correlation between real and imaginary parts + public void polar(double eMagValue, double eMagError, double ePhaseValue, double ePhaseError, double corrCoeff){ + ErrorProp eMag = new ErrorProp(eMagValue, eMagError); + ErrorProp ePhase = new ErrorProp(ePhaseValue, ePhaseError); + polar(eMag, ePhase, corrCoeff); + } + + // Set the value of real + public void setReal(ErrorProp eReal){ + this.eReal = eReal.copy(); + } + + // Set the value of real + public void setReal(double eRealValue, double eRealError){ + this.eReal.setValue(eRealValue); + this.eReal.setError(eRealError); + } + + // Set the value of imag + public void setImag(ErrorProp eImag){ + this.eImag = eImag.copy(); + } + + // Set the value of imag + public void setImag(double eImagValue, double eImagError){ + this.eImag.setValue(eImagValue); + this.eImag.setError(eImagError); + } + + // Set the values of an error free double as ComplexErrorProp + public void setDouble(double errorFree){ + this.eReal.reset(errorFree, 0.0D); + this.eImag.reset(0.0D, 0.0D); + } + + // Set the value of the correlation coefficient between the real and imaginary parts + public void setCorrCoeff(double corrCoeff){ + this.corrCoeff = corrCoeff; + } + + // set value of the Monte Carlo simulation array length + public static void setMonteCarloLength(int length){ + ComplexErrorProp.monteCarloLength = length; + } + + + // GET VALUES + // Get the real part + public ErrorProp getReal(){ + return eReal.copy(); + } + + // Get the value of real + public double getRealValue(){ + return eReal.getValue(); + } + + // Get the error of real + public double getRealError(){ + return eReal.getError(); + } + + // Get the imag part + public ErrorProp getImag(){ + return eImag.copy(); + } + + // Get the value of imag + public double getImagValue(){ + return eImag.getValue(); + } + + // Get the error of eImag + public double getImagError(){ + return eImag.getError(); + } + + // Get the correlation coefficient + public double getCorrCoeff(){ + return this.corrCoeff; + } + + // Get value of the Monte Carlo simulation array length + public static int getMonteCarloLength(){ + return ComplexErrorProp.monteCarloLength; + } + + // COPY + // Copy a single complex error prop number [static method] + public static ComplexErrorProp copy(ComplexErrorProp a){ + if(a==null){ + return null; + } + else{ + ComplexErrorProp b = new ComplexErrorProp(); + b.eReal=a.eReal.copy(); + b.eImag=a.eImag.copy(); + return b; + } + } + + // Copy a single complex error prop number [instance method] + public ComplexErrorProp copy(){ + if(this==null){ + return null; + } + else{ + ComplexErrorProp b = new ComplexErrorProp(); + b.eReal=this.eReal.copy(); + b.eImag=this.eImag.copy(); + return b; + } + } + + //CLONE + // Clone a single complex error prop number + public Object clone(){ + if(this==null){ + return null; + } + else{ + ComplexErrorProp b = new ComplexErrorProp(); + b.eReal=this.eReal.copy(); + b.eImag=this.eImag.copy(); + return (Object) b; + } + } + + // ADDITION + // Add two ComplexErrorProp numbers [static method] + public static ComplexErrorProp plus(ComplexErrorProp a, ComplexErrorProp b){ + ComplexErrorProp c = new ComplexErrorProp(); + c.eReal=a.eReal.plus(b.eReal); + c.eImag=a.eImag.plus(b.eImag); + return c; + } + + //Add a ComplexErrorProp number to this ComplexErrorProp number [instance method] + // this ComplexErrorProp number remains unaltered + public ComplexErrorProp plus(ComplexErrorProp a){ + ComplexErrorProp b = new ComplexErrorProp(); + b.eReal=this.eReal.plus(a.eReal); + b.eImag=this.eImag.plus(a.eImag); + return b; + } + + // SUBTRACTION + //Subtract two ComplexErrorProp numbers [static method] + public static ComplexErrorProp minus (ComplexErrorProp a, ComplexErrorProp b){ + ComplexErrorProp c = new ComplexErrorProp(); + c.eReal=a.eReal.minus(b.eReal); + c.eImag=a.eImag.minus(b.eImag); + return c; + } + + //Subtract a ComplexErrorProp number from this ComplexErrorProp number [instance method] + // this ComplexErrorProp number remains unaltered + public ComplexErrorProp minus(ComplexErrorProp a){ + ComplexErrorProp b = new ComplexErrorProp(); + b.eReal=this.eReal.minus(a.eReal); + b.eImag=this.eImag.minus(a.eImag); + return b; + } + + // MULTIPLICATION + //Multiply two ComplexErrorProp numbers [static method] + public static ComplexErrorProp times(ComplexErrorProp a, ComplexErrorProp b){ + ComplexErrorProp c = new ComplexErrorProp(); + c.eReal=a.eReal.times(b.eReal).minus(a.eImag.times(b.eImag)); + c.eImag=a.eReal.times(b.eImag).plus(a.eImag.times(b.eReal)); + return c; + } + + //Multiply two ComplexErrorProp numbers [instance method] + public ComplexErrorProp times(ComplexErrorProp b){ + ComplexErrorProp c = new ComplexErrorProp(); + c.eReal=this.eReal.times(b.eReal).minus(this.eImag.times(b.eImag)); + c.eImag=this.eReal.times(b.eImag).plus(this.eImag.times(b.eReal)); + return c; + } + + //Multiply this ComplexErrorProp number by a ComplexErrorProp number and replace this by the product + public void timesEquals(ComplexErrorProp a){ + ComplexErrorProp b = new ComplexErrorProp(); + b.eReal=a.eReal.times(this.eReal).minus(a.eImag.times(this.eImag)); + b.eImag=a.eReal.times(this.eImag).plus(a.eImag.times(this.eReal)); + this.eReal=b.eReal.copy(); + this.eImag=b.eImag.copy(); + } + + + // DIVISION + //Division of two ComplexErrorProp numbers a/b [static method] + public static ComplexErrorProp over(ComplexErrorProp a, ComplexErrorProp b){ + ComplexErrorProp c = new ComplexErrorProp(); + PsRandom ran = new PsRandom(); + double[] aReal = ran.gaussianArray(a.eReal.getValue(), a.eReal.getError(), ComplexErrorProp.monteCarloLength); + double[] aImag = ran.gaussianArray(a.eImag.getValue(), a.eImag.getError(), ComplexErrorProp.monteCarloLength); + double[] bReal = ran.gaussianArray(b.eReal.getValue(), b.eReal.getError(), ComplexErrorProp.monteCarloLength); + double[] bImag = ran.gaussianArray(b.eImag.getValue(), b.eImag.getError(), ComplexErrorProp.monteCarloLength); + double[] rat = new double[ComplexErrorProp.monteCarloLength]; + double[] denm = new double[ComplexErrorProp.monteCarloLength]; + double[] cReal = new double[ComplexErrorProp.monteCarloLength]; + double[] cImag = new double[ComplexErrorProp.monteCarloLength]; + + for(int i=0; i<ComplexErrorProp.monteCarloLength; i++){ + + if(Math.abs(bReal[i])>=Math.abs(bImag[i])){ + rat[i] = bImag[i]/bReal[i]; + denm[i] = bReal[i] + bImag[i]*rat[i]; + cReal[i] = (aReal[i] + aImag[i]*rat[i])/denm[i]; + cImag[i] = (aImag[i] - aReal[i]*rat[i])/denm[i]; + } + else{ + rat[i] = bReal[i]/bImag[i]; + denm[i] = bReal[i]*rat[i] + bImag[i]; + cReal[i] = (aReal[i]*rat[i] + aImag[i])/denm[i]; + cImag[i] = (aImag[i]*rat[i] - aReal[i])/denm[i]; + } + } + double cRealSum = 0.0D; + double cImagSum = 0.0D; + double cRealErrorSum = 0.0D; + double cImagErrorSum = 0.0D; + for(int i=0; i<ComplexErrorProp.monteCarloLength; i++){ + cRealSum += cReal[i]; + cImagSum += cImag[i]; + } + cRealSum /= ComplexErrorProp.monteCarloLength; + cImagSum /= ComplexErrorProp.monteCarloLength; + for(int i=0; i<ComplexErrorProp.monteCarloLength; i++){ + cRealErrorSum += Fmath.square(cRealSum - cReal[i]); + cImagErrorSum += Fmath.square(cImagSum - cImag[i]); + } + cRealErrorSum = Math.sqrt(cRealErrorSum/(ComplexErrorProp.monteCarloLength-1)); + cImagErrorSum = Math.sqrt(cImagErrorSum/(ComplexErrorProp.monteCarloLength-1)); + c.eReal.setError(cRealErrorSum); + c.eImag.setError(cImagErrorSum); + + double denom = 0.0D; + double ratio = 0.0D; + if(Math.abs(b.eReal.getValue())>=Math.abs(b.eImag.getValue())){ + ratio=b.eImag.getValue()/b.eReal.getValue(); + denom=b.eReal.getValue()+b.eImag.getValue()*ratio; + c.eReal.setValue((a.eReal.getValue()+a.eImag.getValue()*ratio)/denom); + c.eImag.setValue((a.eImag.getValue()-a.eReal.getValue()*ratio)/denom); + } + else{ + ratio=b.eReal.getValue()/b.eImag.getValue(); + denom=b.eReal.getValue()*ratio+b.eImag.getValue(); + c.eReal.setValue((a.eReal.getValue()*ratio+a.eImag.getValue())/denom); + c.eImag.setValue((a.eImag.getValue()*ratio-a.eReal.getValue())/denom); + } + return c; + } + //Division of this ComplexErrorProp number by a ComplexErrorProp number [instance method] + // this ComplexErrorProp number remains unaltered + public ComplexErrorProp over(ComplexErrorProp b){ + ComplexErrorProp c = new ComplexErrorProp(); + PsRandom ran = new PsRandom(); + double[] aReal = ran.gaussianArray(this.eReal.getValue(), this.eReal.getError(), ComplexErrorProp.monteCarloLength); + double[] aImag = ran.gaussianArray(this.eImag.getValue(), this.eImag.getError(), ComplexErrorProp.monteCarloLength); + double[] bReal = ran.gaussianArray(b.eReal.getValue(), b.eReal.getError(), ComplexErrorProp.monteCarloLength); + double[] bImag = ran.gaussianArray(b.eImag.getValue(), b.eImag.getError(), ComplexErrorProp.monteCarloLength); + double[] rat = new double[ComplexErrorProp.monteCarloLength]; + double[] denm = new double[ComplexErrorProp.monteCarloLength]; + double[] cReal = new double[ComplexErrorProp.monteCarloLength]; + double[] cImag = new double[ComplexErrorProp.monteCarloLength]; + + for(int i=0; i<ComplexErrorProp.monteCarloLength; i++){ + + if(Math.abs(bReal[i])>=Math.abs(bImag[i])){ + rat[i] = bImag[i]/bReal[i]; + denm[i] = bReal[i] + bImag[i]*rat[i]; + cReal[i] = (aReal[i] + aImag[i]*rat[i])/denm[i]; + cImag[i] = (aImag[i] - aReal[i]*rat[i])/denm[i]; + } + else{ + rat[i] = bReal[i]/bImag[i]; + denm[i] = bReal[i]*rat[i] + bImag[i]; + cReal[i] = (aReal[i]*rat[i] + aImag[i])/denm[i]; + cImag[i] = (aImag[i]*rat[i] - aReal[i])/denm[i]; + } + } + double cRealSum = 0.0D; + double cImagSum = 0.0D; + double cRealErrorSum = 0.0D; + double cImagErrorSum = 0.0D; + for(int i=0; i<ComplexErrorProp.monteCarloLength; i++){ + cRealSum += cReal[i]; + cImagSum += cImag[i]; + } + cRealSum /= ComplexErrorProp.monteCarloLength; + cImagSum /= ComplexErrorProp.monteCarloLength; + for(int i=0; i<ComplexErrorProp.monteCarloLength; i++){ + cRealErrorSum += Fmath.square(cRealSum - cReal[i]); + cImagErrorSum += Fmath.square(cImagSum - cImag[i]); + } + cRealErrorSum = Math.sqrt(cRealErrorSum/(ComplexErrorProp.monteCarloLength-1)); + cImagErrorSum = Math.sqrt(cImagErrorSum/(ComplexErrorProp.monteCarloLength-1)); + c.eReal.setError(cRealErrorSum); + c.eImag.setError(cImagErrorSum); + + double denom = 0.0D; + double ratio = 0.0D; + if(Math.abs(b.eReal.getValue())>=Math.abs(b.eImag.getValue())){ + ratio=b.eImag.getValue()/b.eReal.getValue(); + denom=b.eReal.getValue()+b.eImag.getValue()*ratio; + c.eReal.setValue((this.eReal.getValue()+this.eImag.getValue()*ratio)/denom); + c.eImag.setValue((this.eImag.getValue()-this.eReal.getValue()*ratio)/denom); + } + else{ + ratio=b.eReal.getValue()/b.eImag.getValue(); + denom=b.eReal.getValue()*ratio+b.eImag.getValue(); + c.eReal.setValue((this.eReal.getValue()*ratio+this.eImag.getValue())/denom); + c.eImag.setValue((this.eImag.getValue()*ratio-this.eReal.getValue())/denom); + } + return c; + } + + //Exponential [static method] + public static ComplexErrorProp exp(ComplexErrorProp aa){ + ComplexErrorProp bb = new ComplexErrorProp(); + ErrorProp pre = ErrorProp.exp(aa.eReal); + bb.eReal = pre.times(ErrorProp.cos(aa.eImag),aa.corrCoeff); + bb.eImag = pre.times(ErrorProp.sin(aa.eImag),aa.corrCoeff); + return bb; + } + + //Exponential [instance method] + public ComplexErrorProp exp(){ + ComplexErrorProp bb = new ComplexErrorProp(); + ErrorProp pre = ErrorProp.exp(this.eReal); + bb.eReal = pre.times(ErrorProp.cos(this.eImag),this.corrCoeff); + bb.eImag = pre.times(ErrorProp.sin(this.eImag),this.corrCoeff); + return bb; + + } + + //Absolute value (modulus) [static method] + public static ErrorProp abs(ComplexErrorProp aa){ + ErrorProp bb = new ErrorProp(); + double realV = aa.eReal.getValue(); + double imagV = aa.eImag.getValue(); + + double rmod = Math.abs(realV); + double imod = Math.abs(imagV); + double ratio = 0.0D; + double res = 0.0D; + + if(rmod==0.0){ + res=imod; + } + else{ + if(imod==0.0){ + res=rmod; + } + if(rmod>=imod){ + ratio=imagV/realV; + res=rmod*Math.sqrt(1.0 + ratio*ratio); + } + else + { + ratio=realV/imagV; + res=imod*Math.sqrt(1.0 + ratio*ratio); + } + } + bb.setValue(res); + + double realE = aa.eReal.getError(); + double imagE = aa.eImag.getError(); + res = hypotWithRho(2.0D*realE*realV, 2.0D*imagE*imagV, aa.corrCoeff); + bb.setError(res); + + return bb; + } + + //Absolute value (modulus) [instance method] + public ErrorProp abs(){ + ErrorProp aa = new ErrorProp(); + double realV = this.eReal.getValue(); + double imagV = this.eImag.getValue(); + + double rmod = Math.abs(realV); + double imod = Math.abs(imagV); + double ratio = 0.0D; + double res = 0.0D; + + if(rmod==0.0){ + res=imod; + } + else{ + if(imod==0.0){ + res=rmod; + } + if(rmod>=imod){ + ratio=imagV/realV; + res=rmod*Math.sqrt(1.0 + ratio*ratio); + } + else + { + ratio=realV/imagV; + res=imod*Math.sqrt(1.0 + ratio*ratio); + } + } + aa.setValue(res); + + double realE = this.eReal.getError(); + double imagE = this.eImag.getError(); + res = hypotWithRho(2.0D*realE*realV, 2.0D*imagE*imagV, this.corrCoeff); + aa.setError(res); + + return aa; + } + + //Argument of a ComplexErrorProp [static method] + public static ErrorProp arg(ComplexErrorProp a){ + ErrorProp b = new ErrorProp(); + b = ErrorProp.atan2(a.eReal, a.eImag, a.corrCoeff); + return b; + } + + //Argument of a ComplexErrorProp [instance method] + public ErrorProp arg(double rho){ + ErrorProp a = new ErrorProp(); + a = ErrorProp.atan2(this.eReal, this.eImag, this.corrCoeff); + return a; + } + + // Returns sqrt(a*a+b*b + 2*a*b*rho) [without unecessary overflow or underflow] + public static double hypotWithRho(double aa, double bb, double rho){ + double amod=Math.abs(aa); + double bmod=Math.abs(bb); + double cc = 0.0D, ratio = 0.0D; + if(amod==0.0){ + cc=bmod; + } + else{ + if(bmod==0.0){ + cc=amod; + } + else{ + if(amod>=bmod){ + ratio=bmod/amod; + cc=amod*Math.sqrt(1.0 + ratio*ratio + 2.0*rho*ratio); + } + else{ + ratio=amod/bmod; + cc=bmod*Math.sqrt(1.0 + ratio*ratio + 2.0*rho*ratio); + } + } + } + return cc; + } + + // TRUNCATION + // Rounds the mantissae of both the value and error parts of Errorprop to prec places + public static ComplexErrorProp truncate(ComplexErrorProp x, int prec){ + if(prec<0)return x; + + double rV = x.eReal.getValue(); + double rE = x.eReal.getError(); + double iV = x.eImag.getValue(); + double iE = x.eImag.getError(); + ComplexErrorProp y = new ComplexErrorProp(); + + rV = Fmath.truncate(rV, prec); + rE = Fmath.truncate(rE, prec); + iV = Fmath.truncate(iV, prec); + iE = Fmath.truncate(iE, prec); + + y.reset(rV, rE, iV, iE); + return y; + } + + // instance method + public ComplexErrorProp truncate(int prec){ + if(prec<0)return this; + + double rV = this.eReal.getValue(); + double rE = this.eReal.getError(); + double iV = this.eImag.getValue(); + double iE = this.eImag.getError(); + + ComplexErrorProp y = new ComplexErrorProp(); + + rV = Fmath.truncate(rV, prec); + rE = Fmath.truncate(rE, prec); + iV = Fmath.truncate(iV, prec); + iE = Fmath.truncate(iE, prec); + + y.reset(rV, rE, iV, iE); + return y; + } + + // CONVERSIONS + // Format a ComplexErrorProp number as a string + // Overides java.lang.String.toString() + public String toString(){ + return "Real part: " + this.eReal.getValue() + ", error = " + this.eReal.getError() + "; Imaginary part: " + this.eImag.getValue() + ", error = " + this.eImag.getError(); + } + + // Format a ComplexErrorProp number as a string + // See static method above for comments + public static String toString(ComplexErrorProp aa){ + return "Real part: " + aa.eReal.getValue() + ", error = " + aa.eReal.getError() + "; Imaginary part: " + aa.eImag.getValue() + ", error = " + aa.eImag.getError(); + } + + //PRINT AN COMPLEX ERROR NUMBER + // Print to terminal window with text (message) and a line return + public void println(String message){ + System.out.println(message + " " + this.toString()); + } + + // Print to terminal window without text (message) but with a line return + public void println(){ + System.out.println(" " + this.toString()); + } + + // Print to terminal window with text (message) but without line return + public void print(String message){ + System.out.print(message + " " + this.toString()); + } + + // Print to terminal window without text (message) and without line return + public void print(){ + System.out.print(" " + this.toString()); + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/complex/ComplexMatrix.java b/src/main/java/flanagan/complex/ComplexMatrix.java new file mode 100755 index 0000000000000000000000000000000000000000..79211495a52acca0ae3bacf52afcb5e185d62199 --- /dev/null +++ b/src/main/java/flanagan/complex/ComplexMatrix.java @@ -0,0 +1,1475 @@ +/* +* Class ComplexMatrix +* +* Defines a complex matrix and includes the methods +* needed for standard matrix manipulations, e.g. multiplation, +* and related procedures, e.g. solution of complex linear +* simultaneous equations +* +* See class PhasorMatrix for phasor matrix manipulation +* See class Complex for standard complex arithmetic +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: June 2002 +* UPDATES: 16 February 2006 Set methods corrected thanks to Myriam Servieres, Equipe IVC , Ecole Polytechnique de l'université de Nantes, Laboratoire IRCCyN/UMR CNRS +* 7 March 2006 +* 31 March 2006 Norm methods corrected thanks to Jinshan Wu, University of British Columbia +* 22 April 2006 getSubMatrix corrected thanks to Joachim Wesner +* 1 July 2007 dividsion and extra conversion methods added +* 19 April 2008 rowMatrix and columnMatrix added +* 8 October 2008 inverse methods updated +* 16 June 2009 timesEquals corrected thanks to Bjorn Nordstom, Ericsonn +* 5 November 2009 Reduced Row Echelon Form added +* +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ComplexMatrix.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2009 Michael Thomas Flanagan + +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.complex; + +import flanagan.math.*; + +public class ComplexMatrix{ + + private int nrow = 0; // number of rows + private int ncol = 0; // number of columns + private Complex matrix[][] = null; // 2-D Complex Matrix + private int index[] = null; // row permutation index + private double dswap = 1.0D; // row swap index + private static final double TINY = 1.0e-30; + +/*********************************************************/ + + // CONSTRUCTORS + // Construct a nrow x ncol matrix of complex variables all equal to zero + public ComplexMatrix(int nrow, int ncol){ + this.nrow = nrow; + this.ncol = ncol; + this.matrix = Complex.twoDarray(nrow, ncol); + this.index = new int[nrow]; + for(int i=0;i<nrow;i++)this.index[i]=i; + this.dswap=1.0; + } + + // Construct a nrow x ncol matrix of complex variables all equal to the complex number const + public ComplexMatrix(int nrow, int ncol, Complex constant){ + this.nrow = nrow; + this.ncol = ncol; + this.matrix = Complex.twoDarray(nrow, ncol, constant); + this.index = new int[nrow]; + for(int i=0;i<nrow;i++)this.index[i]=i; + this.dswap=1.0; + } + + // Construct matrix with a copy of an existing nrow x ncol 2-D array of complex variables + public ComplexMatrix(Complex[][] twoD){ + this.nrow = twoD.length; + this.ncol = twoD[0].length; + this.matrix = Complex.twoDarray(nrow, ncol); + for(int i=0; i<nrow; i++){ + if(twoD[i].length!=ncol)throw new IllegalArgumentException("All rows must have the same length"); + for(int j=0; j<ncol; j++){ + this.matrix[i][j]=Complex.copy(twoD[i][j]); + } + } + this.index = new int[nrow]; + for(int i=0;i<nrow;i++)this.index[i]=i; + this.dswap=1.0; + } + + // Construct matrix with a copy of an existing nrow x ncol 2-D array of double variables + public ComplexMatrix(double[][] twoD){ + this.nrow = twoD.length; + this.ncol = twoD[0].length; + for(int i=0; i<nrow; i++){ + if(twoD[i].length!=ncol)throw new IllegalArgumentException("All rows must have the same length"); + } + this.matrix = Complex.twoDarray(nrow, ncol); + for(int i=0; i<nrow; i++){ + for(int j=0; j<ncol; j++){ + this.matrix[i][j] = new Complex(twoD[i][j], 0.0); + } + } + this.index = new int[nrow]; + for(int i=0;i<nrow;i++)this.index[i]=i; + this.dswap=1.0; + } + + // Construct matrix with a copy of the complex matrix and permutation index of an existing ComplexMatrix bb. + public ComplexMatrix(ComplexMatrix bb){ + this.nrow = bb.nrow; + this.ncol = bb.ncol; + this.matrix = (bb.copy()).matrix; + this.index = bb.index; + this.dswap = bb.dswap; + } + + // Construct matrix with a copy of the 2D matrix and permutation index of an existing Matrix bb. + public ComplexMatrix(Matrix bb){ + this.nrow = bb.getNrow(); + this.ncol = bb.getNcol(); + double[][] array = bb.getArrayCopy(); + this.matrix = Complex.twoDarray(nrow, ncol); + for(int i=0; i<nrow; i++){ + for(int j=0; j<ncol; j++){ + this.matrix[i][j] = new Complex(array[i][j], 0.0); + } + } + this.index = bb.getIndexCopy(); + this.dswap = bb.getSwap(); + } + + + // SET VALUES + // Set the matrix with a copy of an existing nrow x ncol 2-D matrix of complex variables + public void setTwoDarray(Complex[][] aarray){ + if(this.nrow != aarray.length)throw new IllegalArgumentException("row length of this ComplexMatrix differs from that of the 2D array argument"); + if(this.ncol != aarray[0].length)throw new IllegalArgumentException("column length of this ComplexMatrix differs from that of the 2D array argument"); + for(int i=0; i<nrow; i++){ + if(aarray[i].length!=ncol)throw new IllegalArgumentException("All rows must have the same length"); + for(int j=0; j<ncol; j++){ + this.matrix[i][j]=Complex.copy(aarray[i][j]); + } + } + } + + // Set the matrix with a copy of an existing nrow x ncol 2-D matrix of double variables + public void setTwoDarray(double[][] aarray){ + if(this.nrow != aarray.length)throw new IllegalArgumentException("row length of this ComplexMatrix differs from that of the 2D array argument"); + if(this.ncol != aarray[0].length)throw new IllegalArgumentException("column length of this ComplexMatrix differs from that of the 2D array argument"); + for(int i=0; i<nrow; i++){ + if(aarray[i].length!=ncol)throw new IllegalArgumentException("All rows must have the same length"); + for(int j=0; j<ncol; j++){ + this.matrix[i][j]=new Complex(aarray[i][j]); + } + } + } + + // Set an individual array element + // i = row index + // j = column index + // aa = value of the element + public void setElement(int i, int j, Complex aa){ + this.matrix[i][j]=Complex.copy(aa); + } + + // Set an individual array element + // i = row index + // j = column index + // aa = real part of the element + // bb = imag part of the element + public void setElement(int i, int j, double aa, double bb){ + this.matrix[i][j].reset(aa, bb); + } + + // Set a sub-matrix starting with row index i, column index j + + public void setSubMatrix(int i, int j, Complex[][] subMatrix){ + int k = subMatrix.length; + int l = subMatrix[0].length; + if(i>k)throw new IllegalArgumentException("row indices inverted"); + if(j>l)throw new IllegalArgumentException("column indices inverted"); + int n=k-i+1, m=l-j+1; + for(int p=0; p<n; p++){ + for(int q=0; q<m; q++){ + this.matrix[i+p][j+q] = Complex.copy(subMatrix[p][q]); + } + } + } + + // Set a sub-matrix starting with row index i, column index j + // and ending with row index k, column index l + public void setSubMatrix(int i, int j, int k, int l, Complex[][] subMatrix){ + if(i>k)throw new IllegalArgumentException("row indices inverted"); + if(j>l)throw new IllegalArgumentException("column indices inverted"); + int n=k-i+1, m=l-j+1; + for(int p=0; p<n; p++){ + for(int q=0; q<m; q++){ + this.matrix[i+p][j+q] = Complex.copy(subMatrix[p][q]); + } + } + } + + + // Set a sub-matrix + // row = array of row indices + // col = array of column indices + public void setSubMatrix(int[] row, int[] col, Complex[][] subMatrix){ + int n=row.length; + int m=col.length; + for(int p=0; p<n; p++){ + for(int q=0; q<m; q++){ + this.matrix[row[p]][col[q]] = Complex.copy(subMatrix[p][q]); + } + } + } + + + // SPECIAL MATRICES + // Construct a complex identity matrix + public static ComplexMatrix identityMatrix(int nrow){ + ComplexMatrix u = new ComplexMatrix(nrow, nrow); + for(int i=0; i<nrow; i++){ + u.matrix[i][i]=Complex.plusOne(); + } + return u; + } + + // Construct a complex scalar matrix + public static ComplexMatrix scalarMatrix(int nrow, Complex diagconst){ + ComplexMatrix u = new ComplexMatrix(nrow, nrow); + Complex[][] uarray = u.getArrayReference(); + for(int i=0; i<nrow; i++){ + for(int j=i; j<nrow; j++){ + if(i==j){ + uarray[i][j]=Complex.copy(diagconst); + } + } + } + return u; + } + + // Construct a complex diagonal matrix + public static ComplexMatrix diagonalMatrix(int nrow, Complex[] diag){ + if(diag.length!=nrow)throw new IllegalArgumentException("matrix dimension differs from diagonal array length"); + ComplexMatrix u = new ComplexMatrix(nrow, nrow); + Complex[][] uarray = u.getArrayReference(); + for(int i=0; i<nrow; i++){ + for(int j=i; j<nrow; j++){ + if(i==j){ + uarray[i][j]=Complex.copy(diag[i]); + } + } + } + return u; + } + + // COLUMN MATRICES + // Converts a 1-D array of Complex to a column matrix + public static ComplexMatrix columnMatrix(Complex[] darray){ + int nr = darray.length; + ComplexMatrix pp = new ComplexMatrix(nr, 1); + for(int i=0; i<nr; i++)pp.matrix[i][0] = darray[i]; + return pp; + } + + // ROW MATRICES + // Converts a 1-D array of Complex to a row matrix + public static ComplexMatrix rowMatrix(Complex[] darray){ + int nc = darray.length; + ComplexMatrix pp = new ComplexMatrix(1, nc); + for(int i=0; i<nc; i++)pp.matrix[0][i] = darray[i]; + return pp; + } + + // CONVERSIONS + // Converts a 1-D array of Complex to a complex column matrix + public static ComplexMatrix toComplexColumnMatrix(Complex[] carray){ + int nr = carray.length; + ComplexMatrix cc = new ComplexMatrix(nr, 1); + for(int i=0; i<nr; i++)cc.matrix[i][0] = carray[i].copy(); + return cc; + } + + // Converts a 1-D array of doubles to a complex coumn matrix + public static ComplexMatrix toComplexColumnMatrix(double[] darray){ + int nr = darray.length; + ComplexMatrix cc = new ComplexMatrix(nr, 1); + for(int i=0; i<nr; i++)cc.matrix[i][0].reset(darray[i], 0.0D); + return cc; + } + + // Converts a 1-D array of Complex to a complex row matrix + public static ComplexMatrix toComplexRowMatrix(Complex[] carray){ + int nc = carray.length; + ComplexMatrix cc = new ComplexMatrix(1, nc); + for(int i=0; i<nc; i++)cc.matrix[0][i] = carray[i].copy(); + return cc; + } + + // Converts a 1-D array of doubles to a complex row matrix + public static ComplexMatrix toComplexRowMatrix(double[] darray){ + int nc = darray.length; + ComplexMatrix cc = new ComplexMatrix(1, nc); + for(int i=0; i<nc; i++)cc.matrix[0][i].reset(darray[i], 0.0D); + return cc; + } + + // Converts a matrix of doubles (Matrix) to a complex matrix (ComplexMatix) + public static ComplexMatrix toComplexMatrix(Matrix marray){ + int nr = marray.getNrow(); + int nc = marray.getNcol(); + + ComplexMatrix pp = new ComplexMatrix(nr, nc); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + pp.matrix[i][j].reset(marray.getElementCopy(i, j), 0.0D); + } + } + return pp; + } + + // Converts a 2D array of doubles to a complex matrix (ComplexMatix) + public static ComplexMatrix toComplexMatrix(double[][] darray){ + int nr = darray.length; + int nc = darray[0].length; + for(int i=1; i<nr; i++){ + if(darray[i].length!=nc)throw new IllegalArgumentException("All rows must have the same length"); + } + ComplexMatrix pp = new ComplexMatrix(nr, nc); + for(int i=0; i<pp.nrow; i++){ + for(int j=0; j<pp.ncol; j++){ + pp.matrix[i][j].reset(darray[i][j], 0.0D); + } + } + return pp; + } + + // GET VALUES + // Return the number of rows + public int getNrow(){ + return this.nrow; + } + + // Return the number of columns + public int getNcol(){ + return this.ncol; + } + + // Return a reference to the internal 2-D array + public Complex[][] getArrayReference(){ + return this.matrix; + } + + // Return a reference to the internal 2-D array + public Complex[][] getArray(){ + return this.matrix; + } + + // Return a reference to the internal 2-D array + // included for backward compatibility with earlier incorrect documentation + public Complex[][] getArrayPointer(){ + return this.matrix; + } + + // Return a copy of the internal 2-D array + public Complex[][] getArrayCopy(){ + Complex[][] c = new Complex[this.nrow][this.ncol]; + for(int i=0; i<nrow; i++){ + for(int j=0; j<ncol; j++){ + c[i][j]=Complex.copy(matrix[i][j]); + } + } + return c; + } + + // Return a single element of the internal 2-D array + public Complex getElementReference(int i, int j){ + return this.matrix[i][j]; + } + + // Return a reference to a single element of the internal 2-D array + // included for backward compatibility with earlier incorrect documentation + public Complex getElementPointer(int i, int j){ + return this.matrix[i][j]; + } + + // Return a copy of a single element of the internal 2-D array + public Complex getElementCopy(int i, int j){ + return Complex.copy(this.matrix[i][j]); + } + + // Return a sub-matrix starting with row index i, column index j + // and ending with row index k, column index l + public ComplexMatrix getSubMatrix(int i, int j, int k, int l){ + if(i>k)throw new IllegalArgumentException("row indices inverted"); + if(j>l)throw new IllegalArgumentException("column indices inverted"); + int n=k-i+1, m=l-j+1; + ComplexMatrix subMatrix = new ComplexMatrix(n, m); + Complex[][] sarray = subMatrix.getArrayReference(); + for(int p=0; p<n; p++){ + for(int q=0; q<m; q++){ + sarray[p][q]=Complex.copy(this.matrix[i+p][j+q]); + } + } + return subMatrix; + } + + // Return a sub-matrix + // row = array of row indices + // col = array of column indices + public ComplexMatrix getSubMatrix(int[] row, int[] col){ + int n = row.length; + int m = col.length; + ComplexMatrix subMatrix = new ComplexMatrix(n, m); + Complex[][] sarray = subMatrix.getArrayReference(); + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + sarray[i][j]=Complex.copy(this.matrix[row[i]][col[j]]); + } + } + return subMatrix; + } + + // Return a reference to the permutation index array + public int[] getIndexReference(){ + return this.index; + } + + // Return a reference to the permutation index array + public int[] getIndexPointer(){ + return this.index; + } + + // Return a copy of the permutation index array + public int[] getIndexCopy(){ + int[] indcopy = new int[this.nrow]; + for(int i=0; i<this.nrow; i++){ + indcopy[i]=this.index[i]; + } + return indcopy; + } + + // Return the row swap index + public double getSwap(){ + return this.dswap; + } + + // COPY + // Copy a ComplexMatrix [static method] + public static ComplexMatrix copy(ComplexMatrix a){ + if(a==null){ + return null; + } + else{ + int nr = a.getNrow(); + int nc = a.getNcol(); + Complex[][] aarray = a.getArrayReference(); + ComplexMatrix b = new ComplexMatrix(nr,nc); + b.nrow = nr; + b.ncol = nc; + Complex[][] barray = b.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + barray[i][j]=Complex.copy(aarray[i][j]); + } + } + for(int i=0; i<nr; i++)b.index[i] = a.index[i]; + return b; + } + } + + // Copy a ComplexMatrix [instance method] + public ComplexMatrix copy(){ + if(this==null){ + return null; + } + else{ + int nr = this.nrow; + int nc = this.ncol; + ComplexMatrix b = new ComplexMatrix(nr,nc); + Complex[][] barray = b.getArrayReference(); + b.nrow = nr; + b.ncol = nc; + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + barray[i][j]=Complex.copy(this.matrix[i][j]); + } + } + for(int i=0; i<nr; i++)b.index[i] = this.index[i]; + return b; + } + } + + // Clone a ComplexMatrix + public Object clone(){ + if(this==null){ + return null; + } + else{ + int nr = this.nrow; + int nc = this.ncol; + ComplexMatrix b = new ComplexMatrix(nr,nc); + Complex[][] barray = b.getArrayReference(); + b.nrow = nr; + b.ncol = nc; + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + barray[i][j]=Complex.copy(this.matrix[i][j]); + } + } + for(int i=0; i<nr; i++)b.index[i] = this.index[i]; + return (Object) b; + } + } + + // ADDITION + // Add this matrix to matrix B. This matrix remains unaltered [instance method] + public ComplexMatrix plus(ComplexMatrix bmat){ + if((this.nrow!=bmat.nrow)||(this.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=bmat.nrow; + int nc=bmat.ncol; + ComplexMatrix cmat = new ComplexMatrix(nr,nc); + Complex[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j].plus(bmat.matrix[i][j]); + } + } + return cmat; + } + + // Add this matrix to a Comlex 2-D array. [instance method] + public ComplexMatrix plus(Complex[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if((this.nrow!=nr)||(this.ncol!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + ComplexMatrix cmat = new ComplexMatrix(nr,nc); + Complex[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j].plus(bmat[i][j]); + } + } + return cmat; + } + + // Add this matrix to a real matrix B. [instance method] + public ComplexMatrix plus(Matrix bmat){ + int nr=bmat.getNrow(); + int nc=bmat.getNcol(); + if((this.nrow!=nr)||(this.ncol!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + + ComplexMatrix cmat = new ComplexMatrix(nr,nc); + Complex[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j].plus(bmat.getElement(i,j)); + } + } + return cmat; + } + + // Add this matrix to a real 2-D array. [instance method] + public ComplexMatrix plus(double[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if((this.nrow!=nr)||(this.ncol!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + + ComplexMatrix cmat = new ComplexMatrix(nr,nc); + Complex[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j].plus(bmat[i][j]); + } + } + return cmat; + } + + // Add matrices A and B [static method] + public static ComplexMatrix plus(ComplexMatrix amat, ComplexMatrix bmat){ + if((amat.nrow!=bmat.nrow)||(amat.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=amat.nrow; + int nc=amat.ncol; + ComplexMatrix cmat = new ComplexMatrix(nr,nc); + Complex[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=amat.matrix[i][j].plus(bmat.matrix[i][j]); + } + } + return cmat; + } + + // Add matrix B to this matrix [equivalence of +=] + public void plusEquals(ComplexMatrix bmat){ + if((this.nrow!=bmat.nrow)||(this.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=bmat.nrow; + int nc=bmat.ncol; + + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + this.matrix[i][j].plusEquals(bmat.matrix[i][j]); + } + } + } + + // SUBTRACTION + // Subtract matrix B from this matrix. This matrix remains unaltered [instance method] + public ComplexMatrix minus(ComplexMatrix bmat){ + if((this.nrow!=bmat.nrow)||(this.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=this.nrow; + int nc=this.ncol; + ComplexMatrix cmat = new ComplexMatrix(nr,nc); + Complex[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j].minus(bmat.matrix[i][j]); + } + } + return cmat; + } + + // Subtract Comlex 2-D array from this matrix. [instance method] + public ComplexMatrix minus(Complex[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if((this.nrow!=nr)||(this.ncol!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + ComplexMatrix cmat = new ComplexMatrix(nr,nc); + Complex[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j].minus(bmat[i][j]); + } + } + return cmat; + } + + // Subtract a real matrix from a real matrix B. [instance method] + public ComplexMatrix minus(Matrix bmat){ + int nr=bmat.getNrow(); + int nc=bmat.getNcol(); + if((this.nrow!=nr)||(this.ncol!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + + ComplexMatrix cmat = new ComplexMatrix(nr,nc); + Complex[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j].minus(bmat.getElement(i,j)); + } + } + return cmat; + } + + // Subtract a real 2-D array from this matrix. [instance method] + public ComplexMatrix minus(double[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if((this.nrow!=nr)||(this.ncol!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + + ComplexMatrix cmat = new ComplexMatrix(nr,nc); + Complex[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j].minus(bmat[i][j]); + } + } + return cmat; + } + + + // Subtract matrix B from matrix A [static method] + public static ComplexMatrix minus(ComplexMatrix amat, ComplexMatrix bmat){ + if((amat.nrow!=bmat.nrow)||(amat.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=amat.nrow; + int nc=amat.ncol; + ComplexMatrix cmat = new ComplexMatrix(nr,nc); + Complex[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=amat.matrix[i][j].minus(bmat.matrix[i][j]); + } + } + return cmat; + } + + // Subtract matrix B from this matrix [equivlance of -=] + public void minusEquals(ComplexMatrix bmat){ + if((this.nrow!=bmat.nrow)||(this.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=bmat.nrow; + int nc=bmat.ncol; + + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + this.matrix[i][j].minusEquals(bmat.matrix[i][j]); + } + } + } + + // MULTIPLICATION + // Multiply this complex matrix by a complex matrix. [instance method] + // This matrix remains unaltered. + public ComplexMatrix times(ComplexMatrix bmat){ + if(this.ncol!=bmat.nrow)throw new IllegalArgumentException("Nonconformable matrices"); + + ComplexMatrix cmat = new ComplexMatrix(this.nrow, bmat.ncol); + Complex [][] carray = cmat.getArrayReference(); + Complex sum = new Complex(); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<bmat.ncol; j++){ + sum=Complex.zero(); + for(int k=0; k<this.ncol; k++){ + sum.plusEquals(this.matrix[i][k].times(bmat.matrix[k][j])); + } + carray[i][j]=Complex.copy(sum); + } + } + return cmat; + } + + // Multiply this complex matrix by a complex 2-D array. [instance method] + public ComplexMatrix times(Complex[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if(this.ncol!=nr)throw new IllegalArgumentException("Nonconformable matrices"); + + ComplexMatrix cmat = new ComplexMatrix(this.nrow, nc); + Complex [][] carray = cmat.getArrayReference(); + Complex sum = new Complex(); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<nc; j++){ + sum=Complex.zero(); + for(int k=0; k<this.ncol; k++){ + sum.plusEquals(this.matrix[i][k].times(bmat[k][j])); + } + carray[i][j]=Complex.copy(sum); + } + } + return cmat; + } + + // Multiply this complex matrix by a real matrix. [instance method] + // This matrix remains unaltered. + public ComplexMatrix times(Matrix bmat){ + int nr=bmat.getNrow(); + int nc=bmat.getNcol(); + + if(this.ncol!=nr)throw new IllegalArgumentException("Nonconformable matrices"); + + ComplexMatrix cmat = new ComplexMatrix(this.nrow, nc); + Complex [][] carray = cmat.getArrayReference(); + Complex sum = new Complex(); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<nc; j++){ + sum=Complex.zero(); + for(int k=0; k<this.ncol; k++){ + sum.plusEquals(this.matrix[i][k].times(bmat.getElement(k,j))); + } + carray[i][j]=Complex.copy(sum); + } + } + return cmat; + } + + // Multiply this complex matrix by a real 2-D array. [instance method] + public ComplexMatrix times(double[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if(this.ncol!=nr)throw new IllegalArgumentException("Nonconformable matrices"); + + ComplexMatrix cmat = new ComplexMatrix(this.nrow, nc); + Complex [][] carray = cmat.getArrayReference(); + Complex sum = new Complex(); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<nc; j++){ + sum=Complex.zero(); + for(int k=0; k<this.ncol; k++){ + sum.plusEquals(this.matrix[i][k].times(bmat[k][j])); + } + carray[i][j]=Complex.copy(sum); + } + } + return cmat; + } + + // Multiply this complex matrix by a complex constant [instance method] + // This matrix remains unaltered + public ComplexMatrix times(Complex constant){ + ComplexMatrix cmat = new ComplexMatrix(this.nrow, this.ncol); + Complex [][] carray = cmat.getArrayReference(); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + carray[i][j] = this.matrix[i][j].times(constant); + } + } + return cmat; + } + + // Multiply this complex matrix by a real (double) constant [instance method] + // This matrix remains unaltered. + public ComplexMatrix times(double constant){ + ComplexMatrix cmat = new ComplexMatrix(this.nrow, this.ncol); + Complex [][] carray = cmat.getArrayReference(); + Complex cconstant = new Complex(constant, 0.0); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + carray[i][j] = this.matrix[i][j].times(cconstant); + } + } + return cmat; + } + + // Multiply two complex matrices {static method] + public static ComplexMatrix times(ComplexMatrix amat, ComplexMatrix bmat){ + if(amat.ncol!=bmat.nrow)throw new IllegalArgumentException("Nonconformable matrices"); + + ComplexMatrix cmat = new ComplexMatrix(amat.nrow, bmat.ncol); + Complex [][] carray = cmat.getArrayReference(); + Complex sum = new Complex(); + + for(int i=0; i<amat.nrow; i++){ + for(int j=0; j<bmat.ncol; j++){ + sum=Complex.zero(); + for(int k=0; k<amat.ncol; k++){ + sum.plusEquals(amat.matrix[i][k].times(bmat.matrix[k][j])); + } + carray[i][j]=Complex.copy(sum); + } + } + return cmat; + } + + + // Multiply a complex matrix by a complex constant [static method] + public static ComplexMatrix times(ComplexMatrix amat, Complex constant){ + ComplexMatrix cmat = new ComplexMatrix(amat.nrow, amat.ncol); + Complex [][] carray = cmat.getArrayReference(); + + for(int i=0; i<amat.nrow; i++){ + for(int j=0; j<amat.ncol; j++){ + carray[i][j] = amat.matrix[i][j].times(constant); + } + } + return cmat; + } + + // Multiply a complex matrix by a real (double) constant [static method] + public static ComplexMatrix times(ComplexMatrix amat, double constant){ + ComplexMatrix cmat = new ComplexMatrix(amat.nrow, amat.ncol); + Complex [][] carray = cmat.getArrayReference(); + Complex cconstant = new Complex(constant, 0.0); + + for(int i=0; i<amat.nrow; i++){ + for(int j=0; j<amat.ncol; j++){ + carray[i][j] = amat.matrix[i][j].times(cconstant); + } + } + return cmat; + } + + // Multiply this matrix by a complex matrix [equivalence of *=] + public void timesEquals(ComplexMatrix bmat){ + if(this.ncol!=bmat.nrow)throw new IllegalArgumentException("Nonconformable matrices"); + + ComplexMatrix cmat = new ComplexMatrix(this.nrow, bmat.ncol); + Complex [][] carray = cmat.getArrayReference(); + Complex sum = new Complex(); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<bmat.ncol; j++){ + sum=Complex.zero(); + for(int k=0; k<this.ncol; k++){ + sum.plusEquals(this.matrix[i][k].times(bmat.matrix[k][j])); + } + carray[i][j]=Complex.copy(sum); + } + } + + this.nrow = cmat.nrow; + this.ncol = cmat.ncol; + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + this.matrix[i][j] = cmat.matrix[i][j]; + } + } + } + + + + + // Multiply this matrix by a complex constant [equivalence of *=] + public void timesEquals(Complex constant){ + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + this.matrix[i][j].timesEquals(constant); + } + } + } + + // Multiply this matrix by a real (double) constant [equivalence of *=] + public void timesEquals(double constant){ + Complex cconstant = new Complex(constant, 0.0); + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + this.matrix[i][j].timesEquals(cconstant); + } + } + } + + // DIVISION + // Divide this ComplexMatrix by a ComplexMatrix - instance method. + public ComplexMatrix over(ComplexMatrix bmat){ + if((this.nrow!=bmat.nrow)||(this.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + return this.times(bmat.inverse()); + } + + // Divide this matrix by a Complex 2-D array - instance method. + public ComplexMatrix over(Complex[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if((this.nrow!=nr)||(this.ncol!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + + ComplexMatrix cmat = new ComplexMatrix(bmat); + return this.times(cmat.inverse()); + } + + // Divide this ComplexMatrix by a Matrix - instance method. + public ComplexMatrix over(Matrix bmat){ + ComplexMatrix pmat = ComplexMatrix.toComplexMatrix(bmat); + return this.over(pmat); + } + + // Divide this ComplexMatrix by a 2D array of double - instance method. + public ComplexMatrix over(double[][] bmat){ + ComplexMatrix pmat = ComplexMatrix.toComplexMatrix(bmat); + return this.over(pmat); + } + + // Divide this ComplexMatrix by a ComplexMatrix - static method. + public ComplexMatrix over(ComplexMatrix amat, ComplexMatrix bmat){ + if((amat.nrow!=bmat.nrow)||(amat.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + return amat.times(bmat.inverse()); + } + + // Divide this ComplexMatrix by a ComplexMatrix [equivalence of /=] + public void overEquals(ComplexMatrix bmat){ + if((this.nrow!=bmat.nrow)||(this.ncol!=bmat.ncol)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + ComplexMatrix cmat = new ComplexMatrix(bmat); + this.timesEquals(cmat.inverse()); + } + + // INVERSE + // Inverse of a square complex matrix [instance method] + public ComplexMatrix inverse(){ + int n = this.nrow; + if(n!=this.ncol)throw new IllegalArgumentException("Matrix is not square"); + ComplexMatrix invmat = new ComplexMatrix(n, n); + + if(n==1){ + Complex[][] hold = this.getArrayCopy(); + if(hold[0][0].isZero())throw new IllegalArgumentException("Matrix is singular"); + hold[0][0] = Complex.plusOne().over(hold[0][0]); + invmat = new ComplexMatrix(hold); + } + else{ + if(n==2){ + Complex[][] hold = this.getArrayCopy(); + Complex det = (hold[0][0].times(hold[1][1])).minus(hold[0][1].times(hold[1][0])); + if(det.isZero())throw new IllegalArgumentException("Matrix is singular"); + + Complex[][] hold2 = Complex.twoDarray(2,2); + hold2[0][0] = hold[1][1].over(det); + hold2[1][1] = hold[0][0].over(det); + hold2[1][0] = hold[1][0].negate().over(det); + hold2[0][1] = hold[0][1].negate().over(det); + invmat = new ComplexMatrix(hold2); + } + else{ + Complex[] col = new Complex[n]; + Complex[] xvec = new Complex[n]; + Complex[][] invarray = invmat.getArrayReference(); + ComplexMatrix ludmat; + + ludmat = this.luDecomp(); + for(int j=0; j<n; j++){ + for(int i=0; i<n; i++)col[i]=Complex.zero(); + col[j]=Complex.plusOne(); + xvec=ludmat.luBackSub(col); + for(int i=0; i<n; i++)invarray[i][j]=Complex.copy(xvec[i]); + } + } + } + return invmat; + } + + // Inverse of a square complex matrix [static method] + public static ComplexMatrix inverse(ComplexMatrix amat){ + int n = amat.nrow; + if(n!=amat.ncol)throw new IllegalArgumentException("Matrix is not square"); + + ComplexMatrix invmat = new ComplexMatrix(n, n); + + if(n==1){ + Complex[][] hold = amat.getArrayCopy(); + if(hold[0][0].isZero())throw new IllegalArgumentException("Matrix is singular"); + hold[0][0] = Complex.plusOne().over(hold[0][0]); + invmat = new ComplexMatrix(hold); + } + else{ + if(n==2){ + Complex[][] hold = amat.getArrayCopy(); + Complex det = (hold[0][0].times(hold[1][1])).minus(hold[0][1].times(hold[1][0])); + if(det.isZero())throw new IllegalArgumentException("Matrix is singular"); + + Complex[][] hold2 = Complex.twoDarray(2,2); + hold2[0][0] = hold[1][1].over(det); + hold2[1][1] = hold[0][0].over(det); + hold2[1][0] = hold[1][0].negate().over(det); + hold2[0][1] = hold[0][1].negate().over(det); + invmat = new ComplexMatrix(hold2); + } + else{ + Complex[] col = new Complex[n]; + Complex[] xvec = new Complex[n]; + Complex[][] invarray = invmat.getArrayReference(); + ComplexMatrix ludmat; + + ludmat = amat.luDecomp(); + for(int j=0; j<n; j++){ + for(int i=0; i<n; i++)col[i]=Complex.zero(); + col[j]=Complex.plusOne(); + xvec=ludmat.luBackSub(col); + for(int i=0; i<n; i++)invarray[i][j]=Complex.copy(xvec[i]); + } + } + } + return invmat; + } + + // TRANSPOSE + // Transpose of a complex matrix [instance method] + public ComplexMatrix transpose(){ + ComplexMatrix tmat = new ComplexMatrix(this.ncol, this.nrow); + Complex[][] tarray = tmat.getArrayReference(); + for(int i=0; i<this.ncol; i++){ + for(int j=0; j<this.nrow; j++){ + tarray[i][j]=Complex.copy(this.matrix[j][i]); + } + } + return tmat; + } + + // Transpose of a complex matrix [static method] + public static ComplexMatrix transpose(ComplexMatrix amat){ + ComplexMatrix tmat = new ComplexMatrix(amat.ncol, amat.nrow); + Complex[][] tarray = tmat.getArrayReference(); + for(int i=0; i<amat.ncol; i++){ + for(int j=0; j<amat.nrow; j++){ + tarray[i][j]=Complex.copy(amat.matrix[j][i]); + } + } + return tmat; + } + + // COMPLEX CONJUGATE + //Complex Conjugate of a complex matrix [instance method] + public ComplexMatrix conjugate(){ + ComplexMatrix conj = ComplexMatrix.copy(this); + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + conj.matrix[i][j]=this.matrix[i][j].conjugate(); + } + } + return conj; + } + + //Complex Conjugate of a complex matrix [static method] + public static ComplexMatrix conjugate(ComplexMatrix amat){ + ComplexMatrix conj = ComplexMatrix.copy(amat); + for(int i=0; i<amat.nrow; i++){ + for(int j=0; j<amat.ncol; j++){ + conj.matrix[i][j]=amat.matrix[i][j].conjugate(); + } + } + return conj; + } + + // ADJOIN + // Adjoin of a complex matrix [instance method] + public ComplexMatrix adjoin(){ + ComplexMatrix adj = ComplexMatrix.copy(this); + adj=adj.transpose(); + adj=adj.conjugate(); + return adj; + } + + // Adjoin of a complex matrix [static method] + public ComplexMatrix adjoin(ComplexMatrix amat){ + ComplexMatrix adj = ComplexMatrix.copy(amat); + adj=adj.transpose(); + adj=adj.conjugate(); + return adj; + } + + // OPPOSITE + // Opposite of a complex matrix [instance method] + public ComplexMatrix opposite(){ + ComplexMatrix opp = ComplexMatrix.copy(this); + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + opp.matrix[i][j]=this.matrix[i][j].times(Complex.minusOne()); + } + } + return opp; + } + + // Opposite of a complex matrix [static method] + public static ComplexMatrix opposite(ComplexMatrix amat){ + ComplexMatrix opp = ComplexMatrix.copy(amat); + for(int i=0; i<amat.nrow; i++){ + for(int j=0; j<amat.ncol; j++){ + opp.matrix[i][j]=amat.matrix[i][j].times(Complex.minusOne()); + } + } + return opp; + } + + // TRACE + // Trace of a complex matrix [instance method] + public Complex trace(){ + Complex trac = new Complex(0.0, 0.0); + for(int i=0; i<Math.min(this.ncol,this.ncol); i++){ + trac.plusEquals(this.matrix[i][i]); + } + return trac; + } + + // Trace of a complex matrix [static method] + public static Complex trace(ComplexMatrix amat){ + Complex trac = new Complex(0.0, 0.0); + for(int i=0; i<Math.min(amat.ncol,amat.ncol); i++){ + trac.plusEquals(amat.matrix[i][i]); + } + return trac; + } + + // DETERMINANT + // Returns the determinant of a complex square matrix [instance method] + public Complex determinant(){ + int n = this.nrow; + if(n!=this.ncol)throw new IllegalArgumentException("Matrix is not square"); + Complex det = new Complex(); + ComplexMatrix ludmat; + + ludmat = this.luDecomp(); + det.reset(ludmat.dswap,0.0); + for(int j=0; j<n; j++){ + det.timesEquals(ludmat.matrix[j][j]); + } + return det; + } + + // Returns the determinant of a complex square matrix [static method] + public static Complex determinant(ComplexMatrix amat){ + int n = amat.nrow; + if(n!=amat.ncol)throw new IllegalArgumentException("Matrix is not square"); + Complex det = new Complex(); + ComplexMatrix ludmat; + + ludmat = amat.luDecomp(); + det.reset(ludmat.dswap,0.0); + for(int j=0; j<n; j++){ + det.timesEquals(ludmat.matrix[j][j]); + } + return det; + } + + // Returns the log(determinant) of a complex square matrix [instance method]. + // Useful if determinant() underflows or overflows. + public Complex logDeterminant(){ + int n = this.nrow; + if(n!=this.ncol)throw new IllegalArgumentException("Matrix is not square"); + Complex det = new Complex(); + ComplexMatrix ludmat; + + ludmat = this.luDecomp(); + det.reset(ludmat.dswap,0.0); + det=Complex.log(det); + for(int j=0; j<n; j++){ + det.plusEquals(Complex.log(ludmat.matrix[j][j])); + } + return det; + } + + // Returns the log(determinant) of a complex square matrix [static method]. + // Useful if determinant() underflows or overflows. + public static Complex logDeterminant(ComplexMatrix amat){ + int n = amat.nrow; + if(n!=amat.ncol)throw new IllegalArgumentException("Matrix is not square"); + Complex det = new Complex(); + ComplexMatrix ludmat; + + ludmat = amat.luDecomp(); + det.reset(ludmat.dswap,0.0); + det=Complex.log(det); + for(int j=0; j<n; j++){ + det.plusEquals(Complex.log(ludmat.matrix[j][j])); + } + return det; + } + + // REDUCED ROW ECHELON FORM + public ComplexMatrix reducedRowEchelonForm() { + + Complex[][] mat = Complex.twoDarray(this.nrow, this.ncol); + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + mat[i][j] = this.matrix[i][j]; + } + } + + int leadingCoeff = 0; + int rowPointer = 0; + + boolean testOuter = true; + while(testOuter){ + int counter = rowPointer; + boolean testInner = true; + while(testInner && mat[counter][leadingCoeff].equals(Complex.zero())) { + counter++; + if(counter == this.nrow){ + counter = rowPointer; + leadingCoeff++; + if(leadingCoeff == this.ncol)testInner=false; + } + } + if(testInner){ + Complex[] temp = mat[rowPointer]; + mat[rowPointer] = mat[counter]; + mat[counter] = temp; + + Complex pivot = mat[rowPointer][leadingCoeff]; + for(int j=0; j<this.ncol; j++)mat[rowPointer][j] = mat[rowPointer][j].over(pivot); + + for(int i=0; i<this.nrow; i++){ + if (i!=rowPointer) { + pivot = mat[i][leadingCoeff]; + for (int j=0; j<this.ncol; j++)mat[i][j] = mat[i][j].minus(pivot.times(mat[rowPointer][j])); + } + } + leadingCoeff++; + if(leadingCoeff>=this.ncol)testOuter = false; + } + rowPointer++; + if(rowPointer>=this.nrow || !testInner)testOuter = false; + } + + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + if(mat[i][j].getReal()==-0.0)mat[i][j].reset(0.0, mat[i][j].getImag()); + if(mat[i][j].getImag()==-0.0)mat[i][j].reset(mat[i][j].getReal(), 0.0); + } + } + return new ComplexMatrix(mat); + } + + // FROBENIUS NORM of a complex matrix + // Sometimes referred to as the EUCLIDEAN NORM + public double frobeniusNorm(){ + double norm=0.0D; + for(int i=0; i<this.nrow; i++){ + for(int j=0; j<this.ncol; j++){ + norm=Fmath.hypot(norm, Complex.abs(matrix[i][j])); + } + } + return norm; + } + + // ONE NORM of a complex matrix + public double oneNorm(){ + double norm=0.0D; + double sum = 0.0D; + for(int i=0; i<this.nrow; i++){ + sum=0.0D; + for(int j=0; j<this.ncol; j++){ + sum+=Complex.abs(this.matrix[i][j]); + } + norm=Math.max(norm,sum); + } + return norm; + } + + // INFINITY NORM of a complex matrix + public double infinityNorm(){ + double norm=0.0D; + double sum=0.0D; + for(int i=0; i<this.nrow; i++){ + sum=0.0D; + for(int j=0; j<this.ncol; j++){ + sum+=Complex.abs(this.matrix[i][j]); + } + norm=Math.max(norm,sum); + } + return norm; + } + + + // LU DECOMPOSITION OF COMPLEX MATRIX A + // For details of LU decomposition + // See Numerical Recipes, The Art of Scientific Computing + // by W H Press, S A Teukolsky, W T Vetterling & B P Flannery + // Cambridge University Press, http://www.nr.com/ + // ComplexMatrix ludmat is the returned LU decompostion + // int[] index is the vector of row permutations + // dswap returns +1.0 for even number of row interchanges + // returns -1.0 for odd number of row interchanges + public ComplexMatrix luDecomp(){ + if(this.nrow!=this.ncol)throw new IllegalArgumentException("A matrix is not square"); + int n=this.nrow; + int imax=0; + double dum=0.0D, temp=0.0D, big=0.0D; + double[] vv = new double[n]; + Complex sum = new Complex(); + Complex dumm = new Complex(); + + ComplexMatrix ludmat=ComplexMatrix.copy(this); + Complex[][] ludarray = ludmat.getArrayReference(); + + ludmat.dswap=1.0; + for (int i=0;i<n;i++) { + big=0.0; + for (int j=0;j<n;j++){ + if ((temp=Complex.abs(ludarray[i][j])) > big) big=temp; + } + if (big == 0.0) throw new ArithmeticException("Singular matrix"); + vv[i]=1.0/big; + } + for (int j=0;j<n;j++) { + for (int i=0;i<j;i++) { + sum=Complex.copy(ludarray[i][j]); + for (int k=0;k<i;k++) sum.minusEquals(ludarray[i][k].times(ludarray[k][j])); + ludarray[i][j]=Complex.copy(sum); + } + big=0.0; + for (int i=j;i<n;i++) { + sum=Complex.copy(ludarray[i][j]); + for (int k=0;k<j;k++){ + sum.minusEquals(ludarray[i][k].times(ludarray[k][j])); + } + ludarray[i][j]=Complex.copy(sum); + if ((dum=vv[i]*Complex.abs(sum)) >= big) { + big=dum; + imax=i; + } + } + if (j != imax) { + for (int k=0;k<n;k++) { + dumm=Complex.copy(ludarray[imax][k]); + ludarray[imax][k]=Complex.copy(ludarray[j][k]); + ludarray[j][k]=Complex.copy(dumm); + } + ludmat.dswap = -ludmat.dswap; + vv[imax]=vv[j]; + } + ludmat.index[j]=imax; + + if(ludarray[j][j].isZero()){ + ludarray[j][j].reset(TINY, TINY); + } + if(j != n-1) { + dumm=Complex.over(1.0,ludarray[j][j]); + for (int i=j+1;i<n;i++){ + ludarray[i][j].timesEquals(dumm); + } + } + } + return ludmat; + } + + // Solves the set of n linear complex equations A.X=B using not A but its LU decomposition + // Complex bvec is the vector B (input) + // Complex xvec is the vector X (output) + // index is the permutation vector produced by luDecomp() + public Complex[] luBackSub(Complex[] bvec){ + int ii=0,ip=0; + int n=bvec.length; + if(n!=this.ncol)throw new IllegalArgumentException("vector length is not equal to matrix dimension"); + if(this.ncol!=this.nrow)throw new IllegalArgumentException("matrix is not square"); + Complex sum=new Complex(); + Complex[] xvec=new Complex[n]; + for(int i=0; i<n; i++){ + xvec[i]=Complex.copy(bvec[i]); + } + for (int i=0;i<n;i++) { + ip=this.index[i]; + sum=Complex.copy(xvec[ip]); + xvec[ip]=Complex.copy(xvec[i]); + if (ii==0){ + for (int j=ii;j<=i-1;j++){ + sum.minusEquals(this.matrix[i][j].times(xvec[j])); + } + } + else{ + if(sum.isZero()) ii=i; + } + xvec[i]=Complex.copy(sum); + } + for(int i=n-1;i>=0;i--) { + sum=Complex.copy(xvec[i]); + for (int j=i+1;j<n;j++){ + sum.minusEquals(this.matrix[i][j].times(xvec[j])); + } + xvec[i]= sum.over(this.matrix[i][i]); + } + return xvec; + } + + // Solves the set of n linear complex equations A.X=B + // Complex bvec is the vector B (input) + // Complex xvec is the vector X (output) + public Complex[] solveLinearSet(Complex[] bvec){ + ComplexMatrix ludmat; + + ludmat=this.luDecomp(); + return ludmat.luBackSub(bvec); + } +} + diff --git a/src/main/java/flanagan/complex/ComplexPoly.java b/src/main/java/flanagan/complex/ComplexPoly.java new file mode 100755 index 0000000000000000000000000000000000000000..8c123340a5aabc7e4f9f104eee03534db62168aa --- /dev/null +++ b/src/main/java/flanagan/complex/ComplexPoly.java @@ -0,0 +1,1104 @@ +/* +* Class ComplexPoly +* +* Defines a complex polynomial +* y = a[0] + a[1].x + a[2].x^2 + a[3].3 + . . . + a[n].x^n +* where x and all a[i] may be real or complex +* and deg is the degree of the polynomial, i.e. n, +* and includes the methods associated with polynomials, +* e.g. complex root searches +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* See class Complex for standard complex arithmetic +* +* DATE: February 2002 +* UPDATED: 22 June 2003, 19 January 2005, 12 May 2005, 11 October 2005, 30 April 2007 +* 22 November 2007, 10-11 August 2008, 22 August 2008, 31 October 2009, 6 November 2009 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ComplexPoly.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* +* Copyright (c) 2002 - 2009 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.complex; + +import flanagan.io.FileOutput; +import flanagan.io.PrintToScreen; + +public class ComplexPoly{ + + private int deg = 0; // Degree of the polynomial + private int degwz = 0; // Degree of the polynomial with zero roots removed + private Complex[] coeff; // Array of polynomial coefficients + private Complex[] coeffwz; // Array of polynomial coefficients with zero roots removed + + private boolean suppressRootsErrorMessages = false; // = true if suppression of 'null returned' error messages in roots is required + + // CONSTRUCTORS + public ComplexPoly(int n){ + this.deg = n; + this.coeff = Complex.oneDarray(n+1); + } + + // Coefficients are complex + public ComplexPoly(Complex[] aa){ + this.deg =aa.length-1; + this.coeff = Complex.oneDarray(this.deg+1); + for(int i=0; i<=this.deg; i++){ + this.coeff[i]=Complex.copy(aa[i]); + } + } + + // Coefficients are real (double) + public ComplexPoly(double[] aa){ + this.deg =aa.length-1; + coeff = Complex.oneDarray(this.deg+1); + for(int i=0; i<=deg; i++){ + this.coeff[i].reset(aa[i], 0.0); + } + } + + // Coefficients are real (float) + public ComplexPoly(float[] aa){ + this.deg =aa.length-1; + coeff = Complex.oneDarray(this.deg+1); + for(int i=0; i<=deg; i++){ + this.coeff[i].reset((double)aa[i], 0.0); + } + } + + // Coefficients are int + public ComplexPoly(int[] aa){ + this.deg =aa.length-1; + coeff = Complex.oneDarray(this.deg+1); + for(int i=0; i<=deg; i++){ + this.coeff[i].reset((double)aa[i], 0.0); + } + } + + + // Single constant - complex + // y = aa + // needed in class Loop + public ComplexPoly(Complex aa){ + this.deg = 0; + coeff = Complex.oneDarray(1); + this.coeff[0]=Complex.copy(aa); + } + + // Single constant - double + // y = aa + // needed in class Loop + public ComplexPoly(double aa){ + this.deg = 0; + coeff = Complex.oneDarray(1); + this.coeff[0].reset(aa, 0.0); + } + + // Straight line - coefficients are complex + // y = aa + bb.x + public ComplexPoly(Complex aa, Complex bb){ + this.deg = 1; + coeff = Complex.oneDarray(2); + this.coeff[0]=Complex.copy(aa); + this.coeff[1]=Complex.copy(bb); + } + + // Straight line - coefficients are real + // y = aa + bb.x + public ComplexPoly(double aa, double bb){ + this.deg = 1; + coeff = Complex.oneDarray(2); + this.coeff[0].reset(aa, 0.0); + this.coeff[1].reset(bb, 0.0); + } + + // Quadratic - coefficients are complex + // y = aa + bb.x + cc.x^2 + public ComplexPoly(Complex aa, Complex bb, Complex cc){ + this.deg = 2; + coeff = Complex.oneDarray(3); + this.coeff[0]=Complex.copy(aa); + this.coeff[1]=Complex.copy(bb); + this.coeff[2]=Complex.copy(cc); + } + + // Quadratic - coefficients are real + // y = aa + bb.x + cc.x^2 + public ComplexPoly(double aa, double bb, double cc){ + this.deg = 2; + coeff = Complex.oneDarray(3); + this.coeff[0].reset(aa, 0.0); + this.coeff[1].reset(bb, 0.0); + this.coeff[2].reset(cc, 0.0); + } + + // Cubic - coefficients are complex + // y = aa + bb.x + cc.x^2 + dd.x^3 + public ComplexPoly(Complex aa, Complex bb, Complex cc, Complex dd){ + this.deg = 3; + coeff = Complex.oneDarray(4); + this.coeff[0]=Complex.copy(aa); + this.coeff[1]=Complex.copy(bb); + this.coeff[2]=Complex.copy(cc); + this.coeff[3]=Complex.copy(dd); + } + + // Cubic - coefficients are real + // y = aa + bb.x + cc.x^2 + dd.x^3 + public ComplexPoly(double aa, double bb, double cc, double dd){ + this.deg = 3; + coeff = Complex.oneDarray(4); + this.coeff[0].reset(aa, 0.0); + this.coeff[1].reset(bb, 0.0); + this.coeff[2].reset(cc, 0.0); + this.coeff[3].reset(dd, 0.0); + } + + // METHODS + + // Returns a ComplexPoly given the polynomial's roots + public static ComplexPoly rootsToPoly(Complex[] roots){ + if(roots==null)return null; + + int pdeg = roots.length; + + Complex[] rootCoeff = Complex.oneDarray(2); + rootCoeff[0] = roots[0].times(Complex.minusOne()); + rootCoeff[1] = Complex.plusOne(); + ComplexPoly rPoly = new ComplexPoly(rootCoeff); + for(int i=1; i<pdeg; i++){ + rootCoeff[0] = roots[i].times(Complex.minusOne()); + ComplexPoly cRoot = new ComplexPoly(rootCoeff); + rPoly = rPoly.times(cRoot); + } + return rPoly; + } + + // Reset the polynomial + public void resetPoly(Complex [] aa){ + if((this.deg+1)!=aa.length)throw new IllegalArgumentException("array lengths do not match"); + for(int i=0; i<this.deg; i++){ + this.coeff[i] = Complex.copy(aa[i]); + } + } + + // Reset a coefficient + public void resetCoeff(int i, Complex aa){ + this.coeff[i] = Complex.copy(aa); + } + + // Return a copy of this ComplexPoly [instance method] + public ComplexPoly copy(){ + if(this==null){ + return null; + } + else{ + ComplexPoly aa = new ComplexPoly(this.deg); + for(int i=0; i<=this.deg; i++){ + aa.coeff[i] = Complex.copy(this.coeff[i]); + } + aa.deg=this.deg; + return aa; + } + } + + // Return a copy of this ComplexPoly [static] + public static ComplexPoly copy(ComplexPoly bb){ + if(bb==null){ + return null; + } + else{ + ComplexPoly aa = new ComplexPoly(bb.deg); + for(int i=0; i<=bb.deg; i++){ + aa.coeff[i] = Complex.copy(bb.coeff[i]); + } + aa.deg=bb.deg; + return aa; + } + } + + // Clone a ComplexPoly + public Object clone(){ + if(this==null){ + return null; + } + else{ + ComplexPoly aa = new ComplexPoly(this.deg); + for(int i=0; i<=this.deg; i++){ + aa.coeff[i] = Complex.copy(this.coeff[i]); + } + aa.deg=this.deg; + return (Object) aa; + } + } + + // Return a copy of the polynomial + public Complex[] polyNomCopy(){ + Complex[] aa = Complex.oneDarray(this.deg+1); + for(int i=0; i<=this.deg; i++){ + aa[i] = Complex.copy(this.coeff[i]); + } + return aa; + } + + // Return a reference to the polynomial + public Complex[] polyNomReference(){ + return this.coeff; + } + // Return a reference to the polynomial + public Complex[] polyNomPointer(){ + return this.coeff; + } + + // Return a copy of a coefficient + public Complex coeffCopy(int i){ + return Complex.copy(this.coeff[i]); + } + + // Return a reference to a coefficient + public Complex coeffReference(int i){ + return this.coeff[i]; + } + + // Return a reference to a coefficient + public Complex coeffPointer(int i){ + return this.coeff[i]; + } + + // Return the degree + public int getDeg(){ + return this.deg; + } + + // Sets the representation of the square root of minus one to j in Strings + public void setj(){ + Complex.setj(); + } + + // Sets the representation of the square root of minus one to i in Strings + public void seti(){ + Complex.seti(); + } + + // Convert to a String of the form (a+jb)[0] + (a+jb)[1].x + (a+jb)[2].x^2 etc. + public String toString(){ + String ss = ""; + ss = ss + this.coeffCopy(0).toString(); + if(this.deg>0)ss = ss + " + (" + this.coeffCopy(1).toString() + ").x"; + for(int i=2; i<=this.deg; i++){ + ss = ss + " + (" + this.coeffCopy(i).toString() + ").x^" + i; + } + return ss; + } + + // Print the polynomial to screen + public void print(){ + System.out.print(this.toString()); + } + + // Print the polynomial to screen with line return + public void println(){ + System.out.println(this.toString()); + } + + // Print the polynomial to a text file with title + public void printToText(String title){ + title = title + ".txt"; + FileOutput fout = new FileOutput(title, 'n'); + + fout.println("Output File for a ComplexPoly"); + fout.dateAndTimeln(); + fout.println(); + fout.print("Polynomial degree is "); + fout.println(this.deg); + fout.println(); + fout.println("The coefficients are "); + + for(int i=0;i<=this.deg;i++){ + fout.println(this.coeff[i]); + } + fout.println(); + fout.println("End of file."); + fout.close(); + } + + // Print the polynomial to a text file without a given title + public void printToText(){ + String title = "ComplexPolyOut"; + printToText(title); + } + + // LOGICAL TESTS + // Check if two polynomials are identical + public boolean equals(ComplexPoly cp){ + return isEqual(cp); + } + + public boolean isEqual(ComplexPoly cp){ + boolean ret = false; + int nDegThis = this.getDeg(); + int nDegCp = cp.getDeg(); + if(nDegThis==nDegCp){ + boolean test = true; + int i=0; + while(test){ + if(!this.coeff[i].isEqual(cp.coeffReference(i))){ + test = false; + } + else{ + i++; + if(i>nDegCp){ + test = false; + ret = true; + } + } + } + } + return ret; + } + + // Check if two polynomials are identical (static) + public static boolean isEqual(ComplexPoly cp1, ComplexPoly cp2){ + boolean ret = false; + int nDegCp1 = cp1.getDeg(); + int nDegCp2 = cp2.getDeg(); + if(nDegCp1==nDegCp2){ + boolean test = true; + int i=0; + while(test){ + if(!cp1.coeffReference(i).isEqual(cp2.coeffReference(i))){ + test = false; + } + else{ + i++; + if(i>nDegCp1){ + test = false; + ret = true; + } + } + } + } + return ret; + } + + // ADDITION OF TWO POLYNOMIALS + // Addition, instance method + public ComplexPoly plus(ComplexPoly b){ + int n = Math.max(this.deg, b.deg); + ComplexPoly c = new ComplexPoly(n); + if(n==this.deg){ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(this.coeff[i]); + for(int i=0; i<=b.deg; i++)c.coeff[i]=this.coeff[i].plus(b.coeff[i]); + } + else{ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(b.coeff[i]); + for(int i=0; i<=this.deg; i++)c.coeff[i]=this.coeff[i].plus(b.coeff[i]); + } + return c; + } + + // Addition, static method + public static ComplexPoly plus(ComplexPoly a, ComplexPoly b){ + int n = Math.max(a.deg, b.deg); + ComplexPoly c = new ComplexPoly(n); + if(n==a.deg){ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(a.coeff[i]); + for(int i=0; i<=b.deg; i++)c.coeff[i]=a.coeff[i].plus(b.coeff[i]); + } + else{ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(b.coeff[i]); + for(int i=0; i<=a.deg; i++)c.coeff[i]=a.coeff[i].plus(b.coeff[i]); + } + return c; + } + + // Addition of a Complex, instance method + public ComplexPoly plus(Complex bb){ + ComplexPoly b = new ComplexPoly(bb); + int n = Math.max(this.deg, b.deg); + ComplexPoly c = new ComplexPoly(n); + if(n==this.deg){ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(this.coeff[i]); + for(int i=0; i<=b.deg; i++)c.coeff[i]=this.coeff[i].plus(b.coeff[i]); + } + else{ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(b.coeff[i]); + for(int i=0; i<=this.deg; i++)c.coeff[i]=this.coeff[i].plus(b.coeff[i]); + } + return c; + } + + // Addition of a Complex, static method + public static ComplexPoly plus(ComplexPoly a, Complex bb){ + ComplexPoly b = new ComplexPoly(bb); + int n = Math.max(a.deg, b.deg); + ComplexPoly c = new ComplexPoly(n); + if(n==a.deg){ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(a.coeff[i]); + for(int i=0; i<=b.deg; i++)c.coeff[i]=a.coeff[i].plus(b.coeff[i]); + } + else{ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(b.coeff[i]); + for(int i=0; i<=a.deg; i++)c.coeff[i]=a.coeff[i].plus(b.coeff[i]); + } + return c; + } + + // Addition of a double, instance method + public ComplexPoly plus(double bb){ + ComplexPoly b = new ComplexPoly(new Complex(bb, 0.0)); + int n = Math.max(this.deg, b.deg); + ComplexPoly c = new ComplexPoly(n); + if(n==this.deg){ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(this.coeff[i]); + for(int i=0; i<=b.deg; i++)c.coeff[i]=this.coeff[i].plus(b.coeff[i]); + } + else{ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(b.coeff[i]); + for(int i=0; i<=this.deg; i++)c.coeff[i]=this.coeff[i].plus(b.coeff[i]); + } + return c; + } + + // Addition of a double, static method + public static ComplexPoly plus(ComplexPoly a, double bb){ + ComplexPoly b = new ComplexPoly(new Complex(bb, 0.0)); + int n = Math.max(a.deg, b.deg); + ComplexPoly c = new ComplexPoly(n); + if(n==a.deg){ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(a.coeff[i]); + for(int i=0; i<=b.deg; i++)c.coeff[i]=a.coeff[i].plus(b.coeff[i]); + } + else{ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(b.coeff[i]); + for(int i=0; i<=a.deg; i++)c.coeff[i]=a.coeff[i].plus(b.coeff[i]); + } + return c; + } + + // Addition of an int, instance method + public ComplexPoly plus(int bb){ + ComplexPoly b = new ComplexPoly(new Complex((double) bb, 0.0)); + int n = Math.max(this.deg, b.deg); + ComplexPoly c = new ComplexPoly(n); + if(n==this.deg){ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(this.coeff[i]); + for(int i=0; i<=b.deg; i++)c.coeff[i]=this.coeff[i].plus(b.coeff[i]); + } + else{ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(b.coeff[i]); + for(int i=0; i<=this.deg; i++)c.coeff[i]=this.coeff[i].plus(b.coeff[i]); + } + return c; + } + + // Addition of an int, static method + public static ComplexPoly plus(ComplexPoly a, int bb){ + ComplexPoly b = new ComplexPoly(new Complex((double)bb, 0.0)); + int n = Math.max(a.deg, b.deg); + ComplexPoly c = new ComplexPoly(n); + if(n==a.deg){ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(a.coeff[i]); + for(int i=0; i<=b.deg; i++)c.coeff[i]=a.coeff[i].plus(b.coeff[i]); + } + else{ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(b.coeff[i]); + for(int i=0; i<=a.deg; i++)c.coeff[i]=a.coeff[i].plus(b.coeff[i]); + } + return c; + } + + // SUBTRACTION OF TWO POLYNOMIALS + // Subtraction, instance method + public ComplexPoly minus(ComplexPoly b){ + int n = Math.max(this.deg, b.deg); + ComplexPoly c = new ComplexPoly(n); + if(n==this.deg){ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(this.coeff[i]); + for(int i=0; i<=b.deg; i++)c.coeff[i]=this.coeff[i].minus(b.coeff[i]); + } + else{ + for(int i=0; i<=n; i++)c.coeff[i]=(b.coeff[i]).times(Complex.minusOne()); + for(int i=0; i<=this.deg; i++)c.coeff[i]=b.coeff[i].plus(this.coeff[i]); + } + return c; + } + + // Subtraction of a Complex, instance method + public ComplexPoly minus(Complex bb){ + ComplexPoly b = new ComplexPoly(bb); + return this.minus(b); + } + + // Subtraction of a double, instance method + public ComplexPoly minus(double bb){ + ComplexPoly b = new ComplexPoly(new Complex(bb, 0.0)); + return this.minus(b); + } + + // Subtraction, static method + public static ComplexPoly minus(ComplexPoly a, ComplexPoly b){ + int n = Math.max(a.deg, b.deg); + ComplexPoly c = new ComplexPoly(n); + if(n==a.deg){ + for(int i=0; i<=n; i++)c.coeff[i]=Complex.copy(a.coeff[i]); + for(int i=0; i<=b.deg; i++)c.coeff[i]=a.coeff[i].minus(b.coeff[i]); + } + else{ + for(int i=0; i<=n; i++)c.coeff[i]=(b.coeff[i]).times(Complex.minusOne()); + for(int i=0; i<=a.deg; i++)c.coeff[i]=b.coeff[i].plus(a.coeff[i]); + } + return c; + } + + // Subtraction of a Complex, static method + public static ComplexPoly minus(ComplexPoly a, Complex bb){ + ComplexPoly b = new ComplexPoly(bb); + return ComplexPoly.minus(a, b); + } + + + // Subtraction of a double, static method + public static ComplexPoly minus(ComplexPoly a, double bb){ + ComplexPoly b = new ComplexPoly(new Complex(bb, 0.0)); + return ComplexPoly.minus(a, b); + } + + // MULTIPLICATION OF TWO POLYNOMIALS + // Multiplication, instance method + public ComplexPoly times(ComplexPoly b){ + int n = this.deg + b.deg; + ComplexPoly c = new ComplexPoly(n); + for(int i=0; i<=this.deg; i++){ + for(int j=0; j<=b.deg; j++){ + c.coeff[i+j].plusEquals(this.coeff[i].times(b.coeff[j])); + } + } + return c; + } + + // Multiplication, static method + public static ComplexPoly times(ComplexPoly a, ComplexPoly b){ + int n = a.deg + b.deg; + ComplexPoly c = new ComplexPoly(n); + for(int i=0; i<=a.deg; i++){ + for(int j=0; j<=b.deg; j++){ + c.coeff[i+j].plusEquals(a.coeff[i].times(b.coeff[j])); + } + } + return c; + } + + // Multiplication by a Complex, instance method + public ComplexPoly times(Complex bb){ + ComplexPoly b = new ComplexPoly(bb); + int n = this.deg + b.deg; + ComplexPoly c = new ComplexPoly(n); + for(int i=0; i<=this.deg; i++){ + for(int j=0; j<=b.deg; j++){ + c.coeff[i+j].plusEquals(this.coeff[i].times(b.coeff[j])); + } + } + return c; + } + + // Multiplication by a Complex, static method + public static ComplexPoly times(ComplexPoly a, Complex bb){ + ComplexPoly b = new ComplexPoly(bb); + int n = a.deg + b.deg; + ComplexPoly c = new ComplexPoly(n); + for(int i=0; i<=a.deg; i++){ + for(int j=0; j<=b.deg; j++){ + c.coeff[i+j].plusEquals(a.coeff[i].times(b.coeff[j])); + } + } + return c; + } + + // Multiplication by a double, instance method + public ComplexPoly times(double bb){ + ComplexPoly b = new ComplexPoly(new Complex(bb, 0.0)); + int n = this.deg + b.deg; + ComplexPoly c = new ComplexPoly(n); + for(int i=0; i<=this.deg; i++){ + for(int j=0; j<=b.deg; j++){ + c.coeff[i+j].plusEquals(this.coeff[i].times(b.coeff[j])); + } + } + return c; + } + + // Multiplication by a double, static method + public static ComplexPoly times(ComplexPoly a, double bb){ + ComplexPoly b = new ComplexPoly(new Complex(bb, 0.0)); + int n = a.deg + b.deg; + ComplexPoly c = new ComplexPoly(n); + for(int i=0; i<=a.deg; i++){ + for(int j=0; j<=b.deg; j++){ + c.coeff[i+j].plusEquals(a.coeff[i].times(b.coeff[j])); + } + } + return c; + } + + // DERIVATIVES + // Return the coefficients, as a new ComplexPoly, of the nth derivative + public ComplexPoly nthDerivative(int n){ + ComplexPoly dnydxn; + + if(n>this.deg){ + dnydxn = new ComplexPoly(0.0); + } + else{ + dnydxn = new ComplexPoly(this.deg-n); + Complex[] nc = Complex.oneDarray(this.deg - n + 1); + + int k = this.deg - n; + for(int i=this.deg; i>n-1; i--){ + nc[k]=Complex.copy(this.coeff[i]); + for(int j=0; j<n; j++){ + nc[k]=Complex.times(nc[k], i-j); + } + k--; + } + dnydxn = new ComplexPoly(nc); + } + return dnydxn; + } + + // EVALUATION OF A POLYNOMIAL AND ITS DERIVATIVES + // Evaluate the polynomial + public Complex evaluate(Complex x){ + Complex y = new Complex(); + if(this.deg==0){ + y=Complex.copy(this.coeff[0]); + } + else{ + y=Complex.copy(this.coeff[deg]); + for(int i=deg-1; i>=0; i--){ + y=Complex.plus(Complex.times(y, x),this.coeff[i]); + } + } + return y; + } + + public Complex evaluate(double xx){ + Complex x =new Complex(xx,0.0); + Complex y = new Complex(); + if(deg==0){ + y=Complex.copy(this.coeff[0]); + } + else{ + y=Complex.copy(this.coeff[deg]); + for(int i=deg-1; i>=0; i--){ + y=Complex.plus(Complex.times(y, x),this.coeff[i]); + } + } + return y; + } + + // Evaluate the nth derivative of the polynomial + public Complex nthDerivEvaluate(int n, Complex x){ + Complex dnydxn = new Complex(); + Complex[] nc = Complex.oneDarray(this.deg+1); + + if(n==0) + { + dnydxn=this.evaluate(x); + System.out.println("n = 0 in ComplexPoly.nthDerivative"); + System.out.println("polynomial itself evaluated and returned"); + } + else{ + ComplexPoly nthderiv = this.nthDerivative(n); + dnydxn = nthderiv.evaluate(x); + } + return dnydxn; + } + + public Complex nthDerivEvaluate(int n, double xx){ + Complex x = new Complex(xx, 0.0); + return nthDerivEvaluate(n, x); + } + + // ROOTS OF POLYNOMIALS + // For general details of root searching and a discussion of the rounding errors + // see Numerical Recipes, The Art of Scientific Computing + // by W H Press, S A Teukolsky, W T Vetterling & B P Flannery + // Cambridge University Press, http://www.nr.com/ + + // Calculate the roots (real or complex) of a polynomial (real or complex) + // polish = true ([for deg>3 see laguerreAll(...)] + // initial root estimates are all zero [for deg>3 see laguerreAll(...)] + public Complex[] roots(){ + boolean polish=true; + Complex estx = new Complex(0.0, 0.0); + return roots(polish, estx); + } + + // Calculate the roots - as above with the exception that the error messages are suppressed + // Required by BlackBox + public Complex[] rootsNoMessages(){ + this.suppressRootsErrorMessages = true; + return roots(); + } + + // Calculate the roots (real or complex) of a polynomial (real or complex) + // initial root estimates are all zero [for deg>3 see laguerreAll(...)] + // for polish see laguerreAll(...)[for deg>3] + public Complex[] roots(boolean polish){ + Complex estx = new Complex(0.0, 0.0); + return roots(polish, estx); + } + + // Calculate the roots (real or complex) of a polynomial (real or complex) + // for estx see laguerreAll(...)[for deg>3] + // polish = true see laguerreAll(...)[for deg>3] + public Complex[] roots(Complex estx){ + boolean polish=true; + return roots(polish, estx); + } + + // Calculate the roots (real or complex) of a polynomial (real or complex) + public Complex[] roots(boolean polish, Complex estx){ + // degree = 0 - no roots + if(this.deg==0 && !this.suppressRootsErrorMessages){ + System.out.println("degree of the polynomial is zero in the method ComplexPoly.roots"); + System.out.println("null returned"); + return null; + } + + // Check for no roots, i.e all coefficients but the first = 0 + int counter = 0; + for(int i=1; i<this.deg; i++){ + if(this.coeff[i].isZero())counter++; + } + if(counter==this.deg-1 && !this.suppressRootsErrorMessages){ + System.out.println("polynomial coefficients above the zeroth are all zero in the method ComplexPoly.roots"); + System.out.println("null returned"); + return null; + } + + // check for zero roots + boolean testzero=true; + int ii=0, nzeros=0; + while(testzero){ + if(this.coeff[ii].isZero()){ + nzeros++; + ii++; + } + else{ + testzero=false; + } + } + if(nzeros>0){ + this.degwz = this.deg - nzeros; + this.coeffwz = Complex.oneDarray(this.degwz+1); + for(int i=0; i<=this.degwz; i++)this.coeffwz[i] = this.coeff[i + nzeros].copy(); + } + else{ + this.degwz = this.deg; + this.coeffwz = Complex.oneDarray(this.degwz+1); + for(int i=0; i<=this.degwz; i++)this.coeffwz[i] = this.coeff[i].copy(); + } + // calculate non-zero roots + Complex[] roots = Complex.oneDarray(this.deg); + Complex[] root = Complex.oneDarray(this.degwz); + + switch(this.degwz){ + case 1: root[0]=Complex.negate(this.coeffwz[0].over(this.coeffwz[1])); + break; + case 2: root=quadratic(this.coeffwz[0],this.coeffwz[1],this.coeffwz[2]); + break; + case 3: root=cubic(this.coeffwz[0],this.coeffwz[1],this.coeffwz[2], this.coeffwz[3]); + break; + default: root=laguerreAll(polish, estx); + } + + for(int i=0; i<this.degwz; i++){ + roots[i]=root[i].copy(); + } + if(nzeros>0){ + for(int i=this.degwz; i<this.deg; i++){ + roots[i]=Complex.zero(); + } + } + return roots; + } + + // ROOTS OF A QUADRATIC EQUATION + // ax^2 + bx + c = 0 + // roots returned in root[] + // 4ac << b*b accomodated by these methods + public static Complex[] quadratic(Complex c, Complex b, Complex a){ + double qsign=1.0; + Complex qsqrt = new Complex(); + Complex qtest = new Complex(); + Complex bconj = new Complex(); + Complex[] root = Complex.oneDarray(2); + + bconj = b.conjugate(); + qsqrt = Complex.sqrt((Complex.square(b)).minus((a.times(c)).times(4))); + + qtest = bconj.times(qsqrt); + + if( qtest.getReal() < 0.0 ) qsign = -1.0; + + qsqrt = ((qsqrt.over(qsign)).plus(b)).over(-2.0); + root[0] = Complex.over(qsqrt, a); + root[1] = Complex.over(c, qsqrt); + + return root; + } + + public static Complex[] quadratic(double c, double b, double a){ + Complex aa = new Complex(a, 0.0); + Complex bb = new Complex(b, 0.0); + Complex cc = new Complex(c, 0.0); + + return quadratic(cc, bb, aa); + } + + // ROOTS OF A CUBIC EQUATION + // ddx^3 + ccx^2 + bbx + aa = 0 + // roots returned in root[] + + // ROOTS OF A CUBIC EQUATION + // ddx^3 + ccx^2 + bbx + aa = 0 + // roots returned in root[] + public static Complex[] cubic(Complex aa, Complex bb, Complex cc, Complex dd){ + + Complex a = cc.over(dd); + Complex b = bb.over(dd); + Complex c = aa.over(dd); + + Complex[] roots = Complex.oneDarray(3); + + Complex bigQ = ((a.times(a)).minus(b.times(3.0))).over(9.0); + Complex bigR = (((((a.times(a)).times(a)).times(2.0)).minus((a.times(b)).times(9.0))).plus(c.times(27.0))).over(54.0); + + Complex sign = Complex.plusOne(); + Complex bigAsqrtTerm = Complex.sqrt((bigR.times(bigR)).minus((bigQ.times(bigQ)).times(bigQ))); + Complex bigRconjugate = bigR.conjugate(); + if((bigRconjugate.times(bigAsqrtTerm)).getReal()<0.0)sign = Complex.minusOne(); + Complex bigA = (Complex.pow(bigR.plus(sign.times(bigAsqrtTerm)), 1.0/3.0)).times(Complex.minusOne()); + Complex bigB = null; + if(bigA.isZero()){ + bigB = Complex.zero(); + } + else{ + bigB = bigQ.over(bigA); + } + Complex aPlusB = bigA.plus(bigB); + Complex aMinusB = bigA.minus(bigB); + Complex minusAplusB = aPlusB.times(Complex.minusOne()); + Complex aOver3 = a.over(3.0); + Complex isqrt3over2 = new Complex(0.0, Math.sqrt(3.0)/2.0); + roots[0] = aPlusB.minus(aOver3); + roots[1] = ((minusAplusB.over(2.0)).minus(aOver3)).plus(isqrt3over2.times(aMinusB)); + roots[2] = ((minusAplusB.over(2.0)).minus(aOver3)).minus(isqrt3over2.times(aMinusB)); + + return roots; + } + + public static Complex[] cubic(double d, double c, double b, double a){ + Complex aa = new Complex(a, 0.0); + Complex bb = new Complex(b, 0.0); + Complex cc = new Complex(c, 0.0); + Complex dd = new Complex(d, 0.0); + + return cubic(dd, cc, bb, aa); + } + + // LAGUERRE'S METHOD FOR COMPLEX ROOTS OF A COMPLEX POLYNOMIAL + + // Laguerre method for one of the roots + // Following the procedure in Numerical Recipes for C [Reference above] + // estx estimate of the root + // coeff[] coefficients of the polynomial + // m degree of the polynomial + public static Complex laguerre(Complex estx, Complex[] pcoeff, int m){ + double eps = 1e-7; // estimated fractional round-off error + int mr = 8; // number of fractional values in Adam's method of breaking a limit cycle + int mt = 1000; // number of steps in breaking a limit cycle + int maxit = mr*mt; // maximum number of iterations allowed + int niter = 0; // number of iterations taken + + // fractions used to break a limit cycle + double frac[]={0.5, 0.25, 0.75, 0.13, 0.38, 0.62, 0.88, 1.0}; + + Complex root = new Complex(); // root + Complex b = new Complex(); + Complex d = new Complex(); + Complex f = new Complex(); + Complex g = new Complex(); + Complex g2 = new Complex(); + Complex h = new Complex(); + Complex sq = new Complex(); + Complex gp = new Complex(); + Complex gm = new Complex(); + Complex dx = new Complex(); + Complex x1 = new Complex(); + Complex temp1 = new Complex(); + Complex temp2 = new Complex(); + + double abp = 0.0D, abm = 0.0D; + double err = 0.0D, abx = 0.0D; + + for(int i=1; i<=maxit; i++){ + niter=i; + b=Complex.copy(pcoeff[m]); + err=Complex.abs(b); + d=f=Complex.zero(); + abx=Complex.abs(estx); + for(int j=m-1; j>=0;j--) + { + // Efficient computation of the polynomial and its first two derivatives + f=Complex.plus(Complex.times(estx, f), d); + d=Complex.plus(Complex.times(estx, d), b); + b=Complex.plus(Complex.times(estx, b), pcoeff[j]); + err=Complex.abs(b)+abx*err; + } + err*=eps; + + // Estimate of round-off error in evaluating polynomial + if(Complex.abs(b)<=err) + { + root=Complex.copy(estx); + niter=i; + return root; + } + // Laguerre formula + g=Complex.over(d, b); + g2=Complex.square(g); + h=Complex.minus(g2, Complex.times(2.0, Complex.over(f, b))); + sq=Complex.sqrt(Complex.times((double)(m-1), Complex.minus(Complex.times((double)m, h), g2))); + gp=Complex.plus(g, sq); + gm=Complex.minus(g, sq); + abp=Complex.abs(gp); + abm=Complex.abs(gm); + if( abp < abm ) gp = gm; + temp1.setReal((double)m); + temp2.setReal(Math.cos((double)i)); + temp2.setImag(Math.sin((double)i)); + dx=((Math.max(abp, abm) > 0.0 ? Complex.over(temp1, gp):Complex.times(Math.exp(1.0+abx),temp2))); + x1=Complex.minus(estx, dx); + if(Complex.isEqual(estx, x1)) + { + root=Complex.copy(estx); + niter=i; + return root; // converged + } + if ((i % mt)!= 0){ + estx=Complex.copy(x1); + } + else{ + // Every so often we take a fractional step to break any limit cycle + // (rare occurence) + estx=Complex.minus(estx, Complex.times(frac[i/mt-1], dx)); + } + niter=i; + } + // exceeded maximum allowed iterations + root=Complex.copy(estx); + System.out.println("Maximum number of iterations exceeded in laguerre"); + System.out.println("root returned at this point"); + return root; + } + + // Finds all roots of a complex polynomial by successive calls to laguerre + // Following the procedure in Numerical Recipes for C [Reference above] + // Initial estimates are all zero, polish=true + public Complex[] laguerreAll(){ + Complex estx = new Complex(0.0, 0.0); + boolean polish = true; + return laguerreAll(polish, estx); + } + + // Initial estimates estx, polish=true + public Complex[] laguerreAll(Complex estx){ + boolean polish = true; + return laguerreAll(polish, estx); + } + + // Initial estimates are all zero. + public Complex[] laguerreAll(boolean polish){ + Complex estx = new Complex(0.0, 0.0); + return laguerreAll(polish, estx); + } + + // Finds all roots of a complex polynomial by successive calls to laguerre + // Initial estimates are estx + public Complex[] laguerreAll(boolean polish, Complex estx){ + // polish boolean variable + // if true roots polished also by Laguerre + // if false roots returned to be polished by another method elsewhere. + // estx estimate of root - Preferred default value is zero to favour convergence + // to smallest remaining root + + int m = this.degwz; + double eps = 2.0e-6; // tolerance in determining round off in imaginary part + + Complex x = new Complex(); + Complex b = new Complex(); + Complex c = new Complex(); + Complex[] ad = new Complex[m+1]; + Complex[] roots = new Complex[m+1]; + + // Copy polynomial for successive deflation + for(int j=0; j<=m; j++) ad[j]=Complex.copy(this.coeffwz[j]); + + // Loop over each root found + for(int j=m; j>=1; j--){ + x=Complex.copy(estx); // Preferred default value is zero to favour convergence to smallest remaining root + // and find the root + x=laguerre(x, ad, j); + if(Math.abs(x.getImag())<=2.0*eps*Math.abs(x.getReal())) x.setImag(0.0); + roots[j]=Complex.copy(x); + b=Complex.copy(ad[j]); + for(int jj=j-1; jj>=0; jj--){ + c=Complex.copy(ad[jj]); + ad[jj]=Complex.copy(b); + b=(x.times(b)).plus(c); + } + } + + if(polish){ + // polish roots using the undeflated coefficients + for(int j=1; j<=m; j++){ + roots[j]=laguerre(roots[j], this.coeffwz, m); + } + } + + // Sort roots by their real parts by straight insertion + for(int j=2; j<=m; j++){ + x=Complex.copy(roots[j]); + int i=0; + for(i=j-1; i>=1; i--){ + if(roots[i].getReal() <= x.getReal()) break; + roots[i+1]=Complex.copy(roots[i]); + } + roots[i+1]=Complex.copy(x); + } + // shift roots to zero initial index + for(int i=0; i<m; i++)roots[i]=Complex.copy(roots[i+1]); + return roots; + } +} + diff --git a/src/main/java/flanagan/control/AtoD.java b/src/main/java/flanagan/control/AtoD.java new file mode 100755 index 0000000000000000000000000000000000000000..e51e0a1450706cb43baefd95122f4a53fe77b756 --- /dev/null +++ b/src/main/java/flanagan/control/AtoD.java @@ -0,0 +1,482 @@ +/* Class AtoD +* +* This class contains constructor and methods that will +* 1. Simulate an Analogue to Digital Converter (ADC) +* Range may be set to 0 to Vref or -Vref to +Vref +* The former is the default value. +* The quantization error for this ADC is a truncation error +* or +* 2. Simply act as a marker to be used in OpenPath and +* ClosedLoop to indicate the presence of an ADC. +* +* In the latter case the output is equal to the input plus any delay set. +* +* This class is a subclass of the superclass BlackBox. +* +* Author: Michael Thomas Flanagan. +* +* Created: 27 June 2003 +* Revised: 18 August 2003, 5 May 2005, 2 July 2006, 6 April 2008 +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/AtoD.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.control; + +import flanagan.math.*; +import flanagan.complex.*; +import flanagan.control.*; + +public class AtoD extends BlackBox{ + + private int nBits = 0; // Number of bits, n + private long maximumDecimal = 0; // 2^n-1 + private double vRef = 0.0D; // Reference voltage + private int[] vBinary = null; // array holding binary output + private boolean trueAtoD = true; // if true, a real ADC is simulated + // if false, the instance is simply an AtoD marker + private boolean range = true; // if true, range = 0 to vRef + // if false, range = -vRef/2 to +vRef/2 + private double voltageOutput = 0.0D;// if range = true: output voltage corresponding to input voltage truncated by quantiztion error + // if range = false: output voltage equals input voltage + private String binaryOutput = ""; // if range = true: Sting holding the binary representation of the output voltage + private long decimalOutput = 0L; // if range = true: decimal representation of the binary representation of the output + private double sqnr = 0.0D; // signal to quantisation noise ratio + private double input = 0.0D; // input + private double inputC = 0.0D; // input after any clipping + private double shift = 0.0D; // voltage shift (vRef/2) if range is -vRef/2 to +vRef/2 + private long decimalShift = 0L; // voltage shift as decimal represention of its binary representation + private boolean decCalcDone = false; // = true when the decimal output has been calculated + private boolean binCalcDone = false; // = true when the binary output has been calculated + private boolean inputSet = false; // = true when the input has been entered + + private boolean firstCopy = true; // check used by copy method + + // Constructor + // Simulates an ADC + public AtoD(int nBits, double vRef ){ + super("AtoD"); + if(nBits>63)throw new IllegalArgumentException("This program cannot accomadate an ADC simulation with a number of bits greater than 63"); + this.nBits = nBits; + this.maximumDecimal = (long)Math.pow(2, this.nBits)-1L; + this.vRef = vRef; + this.vBinary = new int[nBits+1]; + this.trueAtoD = true; + super.setSnumer(new ComplexPoly(1.0D)); + super.setSdenom(new ComplexPoly(1.0D)); + super.setZtransformMethod(1); + } + + // Constructor + // Simply marks an AtoD event + public AtoD(){ + super("AtoD"); + super.fixedName = "AtoD"; + super.sNumerDeg = 0; + super.sDenomDeg = 0; + super.setSnumer(new ComplexPoly(1.0D)); + super.setSdenom(new ComplexPoly(1.0D)); + super.ztransMethod=1; + super.setZtransformMethod(1); + } + + // Reset range option + // opt = 0 for range 0 to Vref (default option) + // opt = 1 for range -Vref to + vref + public void setRangeOption(int opt){ + if(opt<0 || opt>2)throw new IllegalArgumentException("argument must be either 0 or 1"); + if(opt==0)this.range = true; + if(opt==1){ + this.range = false; + this.shift = this.vRef/2.0D; + this.decimalShift = this.maximumDecimal/2L; + } + if(this.inputSet)this.checkInput(); + this.decCalcDone = false; + } + + // Return the range option + public String getRange(){ + String ran = null; + if(this.trueAtoD){ + if(this.range){ + ran = "0 to "+this.vRef; + } + else{ + ran = "-"+this.vRef/2 + " to "+this.vRef/2; + } + } + else{ + System.out.println("Class AtoD; method getRange()"); + System.out.println("No range option set - this instance of AtoD is an 'ADC marker' only"); + System.out.println("getRangeOption has returned 'ADC marker only'"); + ran = "ADC marker only"; + } + return ran; + } + + // Return the true AtoD option + public boolean getTrueAtoDoption(){ + if(this.trueAtoD){ + System.out.println("This instance of AtoD is a true simulation of an ADC"); + System.out.println("getTrueAtoDoption has returned 'true'"); + } + else{ + System.out.println("This instance of AtoD is not a true simulation of an ADC"); + System.out.println("It is simple an 'A to D marker'"); + System.out.println("getTrueAtoDoption has returned 'false'"); + } + return this.trueAtoD; + } + + // Returns the reference voltage + public double getVref(){ + if(!this.trueAtoD){ + System.out.println("No reference voltage set - this instance of AtoD is an 'ADC marker' only"); + System.out.println("getVref has returned 0.0 V"); + } + return this.vRef; + } + + // Set input + public void setInput(double input){ + this.input = input; + this.checkInput(); + this.inputSet=true; + } + + // Check whether input in range + public void checkInput(){ + this.inputC = input; + if(this.trueAtoD){ + if(this.range){ + if(this.input<0.0D){ + System.out.println("lower limit of the ADC range exceeded"); + System.out.println("input voltage set to zero"); + this.inputC=0.0D; + } + if(this.input>this.vRef){ + System.out.println("upper limit of the ADC range exceeded"); + System.out.println("input voltage set to "+this.vRef); + this.inputC=this.vRef; + } + } + else{ + if(this.input<-this.vRef){ + System.out.println("lower limit of the ADC range exceeded"); + System.out.println("input voltage set to "+(-this.vRef/2)); + this.inputC=-this.vRef/2.0D; + } + if(this.input>this.vRef){ + System.out.println("upper limit of the ADC range exceeded"); + System.out.println("input voltage set to "+this.vRef/2); + this.inputC=this.vRef/2.0D; + } + } + } + this.inputC += this.shift; + this.decCalcDone = false; + this.binCalcDone = false; + } + + + // Return decimal representation of the maximum binary number + public long getMaximumDecimal(){ + if(!this.trueAtoD){ + System.out.println("This instance of AtoD is not a true simulation of an ADC"); + System.out.println("It is simple an 'A to D marker'"); + System.out.println("getTrueAtoDoption has returned 0"); + } + return this.maximumDecimal; + } + + // Return maximum quantization error + public double maximumQuantizationError(){ + double error = 0.0D; + if(this.trueAtoD){ + error = this.vRef/this.maximumDecimal; + } + else{ + System.out.println("This instance of AtoD is not a true simulation of an ADC"); + System.out.println("It is simple an 'A to D marker'"); + System.out.println("getMaxQuantizationError returns zero"); + } + return error; + } + + + + + // Calculate output + public void calcOutput(){ + + if(this.trueAtoD){ + this.decimalOutput = (long)(Math.floor(((this.inputC)/this.vRef)*this.maximumDecimal))-this.decimalShift; + this.voltageOutput = (this.vRef*this.decimalOutput)/this.maximumDecimal; + this.sqnr = 20.0D*Fmath.log10(Math.abs((this.inputC-this.shift)/(this.inputC - this.shift - this.voltageOutput))); + } + else{ + this.voltageOutput = this.input; + this.sqnr = 1.0D/0.0D; + } + + super.sNumer.resetCoeff(0, new Complex(this.voltageOutput/this.input, 0.0D)); + + this.decCalcDone = true; + } + + // Return SQNR (signal to quantization noise ratio) + public double getSQNR(){ + if(!this.decCalcDone)this.calcOutput(); + if(!this.trueAtoD){ + System.out.println("This instance of AtoD is not a true simulation of an ADC"); + System.out.println("It is simple an 'A to D marker'"); + System.out.println("getSQNR returned INFINITY"); + } + return this.sqnr; + } + + // Return output voltage for the given input + // output rescaled to input voltage but with quantization error + public double voltageOutput(){ + if(!this.decCalcDone)this.calcOutput(); + return this.voltageOutput; + } + + // Return decimal representation of the binary output voltage + public long decimalOutput(){ + if(!this.decCalcDone)this.calcOutput(); + if(!this.trueAtoD){ + System.out.println("No formal A to D conversion performed - this instance of AtoD is an 'ADC marker' only"); + System.out.println("decimalOutput has returned 0"); + } + + return this.decimalOutput; + } + + // Convert decimal to binary number of nBits length + // Two's complement + public static int[] decimalToBinary(long decimal, int nBits){ + // check sign and reverse if negative + long decSign = 1L; + if(decimal<0){ + decSign = -1L; + decimal *= decSign; + } + + // check nBits is long enough to accomodate decimal + // if not extend nBits by powers of two + long len = (long)Math.ceil(Math.log(decimal)/Math.log(2)); + if(nBits<len){ + boolean test=true; + int ii=2; + while(test){ + if(Math.pow(2, ii)>len){ + nBits=ii; + test=false; + } + } + } + + // convert positive decimal to binary + int[] binary = new int[nBits]; + for(int i=0; i<nBits; i++)binary[i] = 0; + boolean test = true; + int ii = 0; + while(test){ + binary[ii] = (int) (decimal % 2); + decimal = decimal/2; + ii++; + if(decimal==0)test = false; + } + + // if decimal was entered as negative negate binary + if(decSign==-1L)binary = AtoD.negateBinary(binary); + + return binary; + } + + // Negate a positive binary number + // Two's complement + public static int[] negateBinary(int[] binary){ + int nBinary = binary.length; + int nBin = nBinary; + + // add bit if MSB = 1 and assign it zero to give a two's complement positive number + if(binary[nBinary-1]==1)nBin += nBin; + int[] negate = new int[nBin]; + int[] one = new int[nBin]; + for(int i=0; i<nBin; i++){ + one[i]=0; + negate[i]=1; + } + one[0]=1; + // invert all bits + for(int i=0; i<nBinary; i++){ + if(binary[i] == 1)negate[i] = 0; + } + // add one + negate = AtoD.addBinary(negate, one); + + return negate; + } + + // Add two binary numbers + public static int[] addBinary(int[] aa, int[] bb){ + int n = aa.length; + int m = bb.length; + int lenMax = n; + int lenMin = m; + if(m>n){ + lenMax = m; + lenMin = n; + } + int[] addition = new int[lenMax]; + int carry = 0; + int sum = 0; + for(int i=0; i<lenMin; i++){ + sum = aa[i] + bb[i] + carry; + switch(sum){ + case 0: addition[i] = 0; + carry = 0; + break; + case 1: addition[i] = 1; + carry = 0; + break; + case 2: addition[i] = 0; + carry = 1; + break; + case 3: addition[i] = 1; + carry = 1; + break; + } + } + + return addition; + } + + // Return binary representation of the output + public String binaryOutput(){ + if(!this.decCalcDone)this.calcOutput(); + if(this.trueAtoD){ + int nBit = this.nBits+1; + // shited output to binary + long absDecOut = this.decimalOutput+this.decimalShift; + this.vBinary = AtoD.decimalToBinary(absDecOut, nBit); + + if(this.shift>0.0D){ + // shift, if any, to binary + int[] binaryShift = AtoD.decimalToBinary(this.decimalShift, nBit); + + // negate binary shift + binaryShift = AtoD.negateBinary(binaryShift); + + // add binary to negated shift + this.vBinary = AtoD.addBinary(this.vBinary, binaryShift); + } + + // convert to String + this.binaryOutput=""; + for(int i=nBit-1; i>=0; i--){ + this.binaryOutput = this.binaryOutput + this.vBinary[i]; + } + + } + else{ + System.out.println("No formal A to D conversion performed - this instance of AtoD is an 'ADC marker' only"); + System.out.println("binaryOutput has returned 'null'"); + } + + this.binCalcDone = true; + return this.binaryOutput; + } + + // Return binary representation of the output as an int array + // LSB is the zeroth element + public int[] binaryArray(){ + + if(this.trueAtoD){ + if(!this.binCalcDone)this.binaryOutput(); + } + else{ + System.out.println("No formal A to D conversion performed - this instance of AtoD is an 'ADC marker' only"); + System.out.println("binaryOutput has returned 'null'"); + } + + return this.vBinary; + } + + + // Return quantization error + public double quantizationError(){ + if(!this.decCalcDone)this.calcOutput(); + double error = 0.0D; + if(this.trueAtoD){ + error = this.inputC - this.voltageOutput; + } + else{ + System.out.println("This instance of AtoD is not a true simulation of an ADC"); + System.out.println("It is simple an 'A to D marker'"); + System.out.println("getQuantizationError returns zero"); + } + return error; + } + + // Return any clipping error + public double clippingError(){ + + return this.inputC - this.input; + } + + // Deep copy + public AtoD copy(){ + if(this==null){ + return null; + } + else{ + AtoD bb = new AtoD(); + this.copyBBvariables(bb); + + bb.nBits = this.nBits; + bb.maximumDecimal = this.maximumDecimal; + bb.vRef = this.vRef; + bb.vBinary = this.vBinary.clone(); + bb.trueAtoD = this.trueAtoD; + bb.range = this.range; + bb.voltageOutput = this.voltageOutput; + bb.binaryOutput = this.binaryOutput; + bb.decimalOutput = this.decimalOutput; + bb.sqnr = this.sqnr; + bb.input = this.input; + bb.inputC = this.inputC; + bb.shift = this.shift; + bb.decimalShift = this.decimalShift; + bb.decCalcDone = this.decCalcDone; + bb.binCalcDone = this.binCalcDone; + bb.inputSet = this.inputSet; + + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/control/BlackBox.java b/src/main/java/flanagan/control/BlackBox.java new file mode 100755 index 0000000000000000000000000000000000000000..24ef0fdbe98cfeff534fb33b9079cb7674f78ca9 --- /dev/null +++ b/src/main/java/flanagan/control/BlackBox.java @@ -0,0 +1,2019 @@ +/* Class BlackBox +* +* This class contains the constructor to create an instance of +* a generalised BlackBox with a single input, single output +* and a gain. It contins the methods for obtaining the +* transfer function in the s-domain and the z-domain. +* +* This class is the superclass for several sub-classes, +* e.g. Prop (P controller), PropDeriv (PD controller), +* PropInt (PI controller), PropIntDeriv (PID controller), +* FirstOrder, SecondOrder, AtoD (ADC), DtoA (DAC), +* ZeroOrderHold, DelayLine, OpenLoop (Open Loop Path), +* of use in control engineering. +* +* Author: Michael Thomas Flanagan. +* +* Created: August 2002 +* Updated: 17 July 2003, 18 May 2005, 6 April 2008, 6 October 2009, 30 October 2009, 2-9 November 2009 +* +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/BlackBox.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + + +package flanagan.control; + +import flanagan.math.Fmath; +import flanagan.complex.*; +import flanagan.plot.Plot; +import flanagan.plot.PlotGraph; +import flanagan.plot.PlotPoleZero; + + +public class BlackBox{ + + protected int sampLen = 3; // Length of array of stored inputs, outputs and times + protected double[] inputT = new double[this.sampLen]; // Array of input signal in the time domain + protected double[] outputT = new double[this.sampLen]; // Array of output signal in the time domain + protected double[] time = new double[this.sampLen]; // Array of time at which inputs were taken (seconds) + protected double forgetFactor = 1.0D; // Forgetting factor, e.g. in exponential forgetting of error values + protected double deltaT = 0.0D; // Sampling time (seconds) + protected double sampFreq = 0.0D; // Sampling frequency (Hz) + protected Complex inputS = new Complex(); // Input signal in the s-domain + protected Complex outputS = new Complex(); // Output signal in the s-domain + protected Complex sValue = new Complex(); // Laplacian s + protected Complex zValue = new Complex(); // z-transform z + protected ComplexPoly sNumer = new ComplexPoly(1.0D); // Transfer function numerator in the s-domain + protected ComplexPoly sDenom = new ComplexPoly(1.0D); // Transfer function denominator in the s-domain + protected ComplexPoly zNumer = new ComplexPoly(1.0D); // Transfer function numerator in the z-domain + protected ComplexPoly zDenom = new ComplexPoly(1.0D); // Transfer function denominator in the z-domain + protected boolean sNumerSet = false; // = true when numerator entered + protected boolean sDenomSet = false; // = true when denominator entered + protected Complex sNumerScaleFactor = Complex.plusOne();// s-domain numerator/(product of s - zeros) + protected Complex sDenomScaleFactor = Complex.plusOne();// s-domain denominator/(product of s - poles) + protected Complex sNumerWorkingFactor = Complex.plusOne();// s-domain numerator/(product of s - zeros) at that point in the program + protected Complex sDenomWorkingFactor = Complex.plusOne();// s-domain denominator/(product of s - poles) at that point in the program + protected Complex[] sPoles = null; // Poles in the s-domain + protected Complex[] sZeros = null; // Zeros in the s-domain + protected Complex[] zPoles = null; // Poles in the z-domain + protected Complex[] zZeros = null; // Zeros in the z-domain + protected int sNumerDeg = 0; // Degree of transfer function numerator in the s-domain + protected int sDenomDeg = 0; // Degree of transfer function denominator in the s-domain + protected int zNumerDeg = 0; // Degree of transfer function numerator in the z-domain + protected int zDenomDeg = 0; // Degree of transfer function denominator in the z-domain + protected double deadTime = 0.0D; // Time delay between an input and the matching output [in s-domain = exp(-s.deadTime)] + protected int orderPade = 2; // Order(1 to 4)of the pade approximation for exp(-sT) + // default option = 2 + protected ComplexPoly sNumerPade = new ComplexPoly(1.0D); // Transfer function numerator in the s-domain including Pade approximation + protected ComplexPoly sDenomPade = new ComplexPoly(1.0D); // Transfer function denominator in the s-domain including Pade approximation + protected Complex[] sPolesPade = null; // Poles in the s-domain including Pade approximation + protected Complex[] sZerosPade = null; // Zeros in the s-domain including Pade approximation + protected int sNumerDegPade = 0; // Degree of transfer function numerator in the s-domain including Pade approximation + protected int sDenomDegPade = 0; // Degree of transfer function denominator in the s-domain including Pade approximation + protected boolean maptozero = true; // if true infinity s zeros map to zero + // if false infinity s zeros map to minus one + protected boolean padeAdded = false; // if true Pade poles and zeros added + // if false No Pade poles and zeros added + protected double integrationSum=0.0D; // Stored integration sum in numerical integrations + protected int integMethod = 0; // numerical integration method + // = 0 Trapezium Rule [default option] + // = 1 Backward Rectangular Rule + // = 2 Foreward Rectangular Rule + protected int ztransMethod = 0; // z trasform method + // = 0 s -> z mapping (ad hoc procedure) from the continuous time domain erived s domain functions + // = 1 specific z transform, e.g. of a difference equation + protected String name = "BlackBox"; // Superclass or subclass name, e.g. pid, pd, firstorder. + // user may rename an instance of the superclass or subclass + protected String fixedName = "BlackBox"; // Super class or subclass permanent name, e.g. pid, pd, firstorder. + // user must NOT change fixedName in any instance of the superclass or subclass + // fixedName is used as an identifier in classes such as OpenPath, ClosedLoop + protected int nPlotPoints = 400; // number of points used tp lot response curves, e.g. step input response curve + + protected String[] subclassName = {"BlackBox", "OpenLoop", "ClosedLoop", "Prop", "PropDeriv", "PropInt", "PropIntDeriv", "FirstOrder", "SecondOrder", "Compensator", "LowPassPassive", "HighPassPassive", "Transducer", "DelayLine", "ZeroOrderHold", "AtoD", "DtoA"}; + protected int nSubclasses = subclassName.length; // number of subclasses plus superclass + protected int subclassIndex = 0; // = 0 BlackBox + // = 1 OpenLoop + // = 2 ClosedLoop + // = 3 Prop + // = 4 PropDeriv + // = 5 PropInt + // = 6 PropIntDeriv + // = 7 FirstOrder + // = 8 SecondOrder + // = 9 Compensator + // = 10 LowPassPassive + // = 11 HighPassPassive + // = 12 Transducer + // = 13 DelayLine + // = 14 ZeroOrderHold + // = 15 AtoD + // = 16 DtoA + + // Constructor + public BlackBox(){ + } + + // Constructor with fixedName supplied + // for use by subclasses + public BlackBox(String name){ + this.name = name; + this.fixedName = name; + this.setSubclassIndex(); + } + + // Set subclass index + protected void setSubclassIndex(){ + boolean test = true; + int i = 0; + while(test){ + if(this.fixedName.equals(subclassName[i])){ + this.subclassIndex = i; + test = false; + } + else{ + i++; + if(i>=this.nSubclasses){ + System.out.println("Subclass name, " + this.fixedName + ", not recognised as a recorder subclass"); + System.out.println("Subclass, " + this.fixedName + ", handled as BlackBox"); + this.subclassIndex = i; + test = false; + } + } + } + } + + // Set the transfer function numerator in the s-domain + // Enter as an array of real (double) coefficients of the polynomial a + bs +c.s.s + d.s.s.s + .... + public void setSnumer(double[] coeff){ + this.sNumerDeg = coeff.length-1; + this.sNumer = new ComplexPoly(coeff); + this.sNumerSet = true; + this.calcPolesZerosS(); + this.addDeadTimeExtras(); + } + + // Method to set extra terms to s-domain numerator and denominator and + // to calculate extra zeros and poles if the dead time is not zero. + protected void addDeadTimeExtras() + { + this.sNumerDegPade = this.sNumerDeg; + this.sNumerPade = this.sNumer.copy(); + this.sDenomDegPade = this.sDenomDeg; + this.sDenomPade = this.sDenom.copy(); + + if(this.deadTime==0.0D){ + this.transferPolesZeros(); + } + else{ + this.pade(); + } + + } + + // Set the transfer function numerator in the s-domain + // Enter as an array of Complex coefficients of the polynomial a + bs +c.s.s + d.s.s.s + .... + public void setSnumer(Complex[] coeff){ + this.sNumerDeg = coeff.length-1; + this.sNumer = new ComplexPoly(coeff); + this.sNumerSet = true; + this.calcPolesZerosS(); + this.addDeadTimeExtras(); + + + } + + // Set the transfer function numerator in the s-domain + // Enter as an existing instance of ComplexPoly + public void setSnumer(ComplexPoly coeff){ + this.sNumerDeg = coeff.getDeg(); + this.sNumer = ComplexPoly.copy(coeff); + this.sNumerSet = true; + this.calcPolesZerosS(); + this.addDeadTimeExtras(); + } + + // Set the transfer function denominator in the s-domain + // Enter as an array of real (double) coefficients of the polynomial a + bs +c.s.s + d.s.s.s + .... + public void setSdenom(double[] coeff){ + this.sDenomDeg = coeff.length-1; + this.sDenom = new ComplexPoly(coeff); + this.sDenomSet = true; + this.calcPolesZerosS(); + this.addDeadTimeExtras(); + } + + // Set the transfer function denomonator in the s-domain + // Enter as an array of Complex coefficients of the polynomial a + bs +c.s.s + d.s.s.s + .... + public void setSdenom(Complex[] coeff){ + this.sDenomDeg = coeff.length-1; + this.sDenom = new ComplexPoly(coeff); + this.sDenomSet = true; + this.calcPolesZerosS(); + this.addDeadTimeExtras(); + + } + + // Set the transfer function denominator in the s-domain + // Enter as an existing instance of ComplexPoly + public void setSdenom(ComplexPoly coeff){ + this.sDenomDeg = coeff.getDeg(); + this.sDenom = coeff.copy(); + this.sDenomSet = true; + this.calcPolesZerosS(); + this.addDeadTimeExtras(); + } + + // calculate constant converting product of root terms to the value of the polynomial + public static Complex scaleFactor(ComplexPoly poly, Complex[] roots){ + int nRoots = roots.length; + + // calculate mean of the poles + Complex mean = new Complex(0.0D, 0.0); + for(int i=0; i<nRoots; i++)mean = mean.plus(roots[i]); + mean = mean.over(nRoots); + + // check that mean != a root; increase mean by 1.5 till != any pole + boolean test = true; + int ii=0; + while(test){ + if(mean.isEqual(roots[ii])){ + mean = mean.times(1.5D); + ii=0; + } + else{ + ii++; + if(ii>nRoots-1)test = false; + } + } + + // calculate product of roots-mean + Complex product = new Complex(1.0D, 0.0); + for(int i=0; i<nRoots; i++)product = product.times(mean.minus(roots[i])); + + // evaluate the polynomial at mean value + Complex eval = poly.evaluate(mean); + + // Calculate scaleFactor + return eval.over(product); + } + + // Get numerator scale factor + public Complex getSnumerScaleFactor(){ + if(this.sNumerScaleFactor==null)this.calcPolesZerosS(); + return this.sNumerScaleFactor; + } + + // Get denominator scale factor + public Complex getSdenomScaleFactor(){ + if(this.sDenomScaleFactor==null)this.calcPolesZerosS(); + return this.sDenomScaleFactor; + } + + // Set the dead time + public void setDeadTime(double deadtime){ + this.deadTime = deadtime; + this.pade(); + } + + // Set the dead time and the Pade approximation order + public void setDeadTime(double deadtime, int orderPade){ + this.deadTime = deadtime; + if(orderPade>5){ + orderPade=4; + System.out.println("BlackBox does not support Pade approximations above an order of 4"); + System.out.println("The order has been set to 4"); + } + if(orderPade<1){ + orderPade=1; + System.out.println("Pade approximation order was less than 1"); + System.out.println("The order has been set to 1"); + } + this.orderPade = orderPade; + this.pade(); + } + + // Set the Pade approximation order + public void setPadeOrder(int orderPade){ + if(orderPade>5){ + orderPade=4; + System.out.println("BlackBox does not support Pade approximations above an order of 4"); + System.out.println("The order has been set to 4"); + } + if(orderPade<1){ + orderPade=2; + System.out.println("Pade approximation order was less than 1"); + System.out.println("The order has been set to 2"); + } + this.orderPade = orderPade; + this.pade(); + } + + // Get the dead time + public double getDeadTime(){ + return this.deadTime; + } + + // Get the Pade approximation order + public int getPadeOrder(){ + return this.orderPade; + } + + // Resets the s-domain Pade inclusive numerator and denominator adding a Pade approximation + // Also calculates and stores additional zeros and poles arising from the Pade approximation + protected void pade(){ + ComplexPoly sNumerExtra = null; + ComplexPoly sDenomExtra = null; + Complex[] newZeros = null; + Complex[] newPoles = null; + switch(orderPade){ + case 1: this.sNumerDegPade = this.sNumerDeg + 1; + this.sDenomDegPade = this.sDenomDeg + 1; + this.sNumerPade = new ComplexPoly(sNumerDegPade); + this.sDenomPade = new ComplexPoly(sDenomDegPade); + sNumerExtra = new ComplexPoly(1.0D, -this.deadTime/2.0D); + sDenomExtra = new ComplexPoly(1.0D, this.deadTime/2.0D); + this.sNumerPade = this.sNumer.times(sNumerExtra); + this.sDenomPade = this.sDenom.times(sDenomExtra); + newZeros = Complex.oneDarray(1); + newZeros[0].reset(2.0/this.deadTime, 0.0D); + newPoles = Complex.oneDarray(1); + newPoles[0].reset(-2.0/this.deadTime, 0.0D); + break; + case 2: this.sNumerDegPade = this.sNumerDeg + 2; + this.sDenomDegPade = this.sDenomDeg + 2; + this.sNumerPade = new ComplexPoly(sNumerDegPade); + this.sDenomPade = new ComplexPoly(sDenomDegPade); + sNumerExtra = new ComplexPoly(1.0D, -this.deadTime/2.0D, Math.pow(this.deadTime, 2)/12.0D); + sDenomExtra = new ComplexPoly(1.0D, this.deadTime/2.0D, Math.pow(this.deadTime, 2)/12.0D); + this.sNumerPade = this.sNumer.times(sNumerExtra); + this.sDenomPade = this.sDenom.times(sDenomExtra); + newZeros = sNumerExtra.rootsNoMessages(); + newPoles = sDenomExtra.rootsNoMessages(); + break; + case 3: this.sNumerDegPade = this.sNumerDeg + 3; + this.sDenomDegPade = this.sDenomDeg + 3; + this.sNumerPade = new ComplexPoly(sNumerDegPade); + this.sDenomPade = new ComplexPoly(sDenomDegPade); + double[] termn3 = new double[4]; + termn3[0] = 1.0D; + termn3[1] = -this.deadTime/2.0D; + termn3[2] = Math.pow(this.deadTime, 2)/10.0D; + termn3[3] = -Math.pow(this.deadTime, 3)/120.0D; + sNumerExtra = new ComplexPoly(termn3); + this.sNumerPade = this.sNumer.times(sNumerExtra); + newZeros = sNumerExtra.rootsNoMessages(); + double[] termd3 = new double[4]; + termd3[0] = 1.0D; + termd3[1] = this.deadTime/2.0D; + termd3[2] = Math.pow(this.deadTime, 2)/10.0D; + termd3[3] = Math.pow(this.deadTime, 3)/120.0D; + sDenomExtra = new ComplexPoly(termd3); + this.sDenomPade = this.sDenom.times(sDenomExtra); + newPoles = sDenomExtra.rootsNoMessages(); + break; + case 4: this.sNumerDegPade = this.sNumerDeg + 4; + this.sDenomDegPade = this.sDenomDeg + 4; + this.sNumerPade = new ComplexPoly(sNumerDegPade); + this.sDenomPade = new ComplexPoly(sDenomDegPade); + double[] termn4 = new double[5]; + termn4[0] = 1.0D; + termn4[1] = -this.deadTime/2.0D; + termn4[2] = 3.0D*Math.pow(this.deadTime, 2)/28.0D; + termn4[3] = -Math.pow(this.deadTime, 3)/84.0D; + termn4[4] = Math.pow(this.deadTime, 4)/1680.0D; + sNumerExtra = new ComplexPoly(termn4); + this.sNumerPade = this.sNumer.times(sNumerExtra); + newZeros = sNumerExtra.rootsNoMessages(); + double[] termd4 = new double[5]; + termd4[0] = 1.0D; + termd4[1] = this.deadTime/2.0D; + termd4[2] = 3.0D*Math.pow(this.deadTime, 2)/28.0D; + termd4[3] = Math.pow(this.deadTime, 3)/84.0D; + termd4[4] = Math.pow(this.deadTime, 4)/1680.0D; + sDenomExtra = new ComplexPoly(termd4); + this.sDenomPade = this.sDenom.times(sDenomExtra); + newPoles = sDenomExtra.rootsNoMessages(); + break; + default: this.orderPade = 2; + this.sNumerDegPade = this.sNumerDeg + 2; + this.sDenomDegPade = this.sDenomDeg + 2; + this.sNumerPade = new ComplexPoly(sNumerDegPade); + this.sDenomPade = new ComplexPoly(sDenomDegPade); + sNumerExtra = new ComplexPoly(1.0D, -this.deadTime/2.0D, Math.pow(this.deadTime, 2)/12.0D); + sDenomExtra = new ComplexPoly(1.0D, this.deadTime/2.0D, Math.pow(this.deadTime, 2)/12.0D); + this.sNumerPade = this.sNumer.times(sNumerExtra); + this.sDenomPade = this.sDenom.times(sDenomExtra); + newZeros = sNumerExtra.rootsNoMessages(); + newPoles = sDenomExtra.rootsNoMessages(); + break; + } + + // store zeros and poles arising from the Pade term + if(this.sNumerPade!=null && this.sNumerDegPade>0){ + sZerosPade = Complex.oneDarray(sNumerDegPade); + for(int i=0; i<sNumerDeg; i++){ + sZerosPade[i] = sZeros[i].copy(); + } + for(int i=0; i<this.orderPade; i++){ + sZerosPade[i+sNumerDeg] = newZeros[i].copy(); + } + } + + if(this.sDenomPade!=null && this.sDenomDegPade>0){ + sPolesPade = Complex.oneDarray(sDenomDegPade); + for(int i=0; i<sDenomDeg; i++){ + sPolesPade[i] = sPoles[i].copy(); + } + for(int i=0; i<this.orderPade; i++){ + sPolesPade[i+sDenomDeg] = newPoles[i].copy(); + } + } + this.zeroPoleCancellation(); + this.padeAdded = true; + } + + // Copies s-domain poles and zeros from the s-domain arrays to the s-domain Pade arrays + // used when deadTime is zero + protected void transferPolesZeros(){ + + this.sNumerDegPade = this.sNumerDeg; + this.sNumerPade = this.sNumer.copy(); + if(this.sNumerDeg>0 && this.sZeros!=null){ + this.sZerosPade = Complex.oneDarray(this.sNumerDeg); + for(int i=0; i<this.sNumerDeg; i++)this.sZerosPade[i] = this.sZeros[i].copy(); + } + + this.sDenomDegPade = this.sDenomDeg; + this.sDenomPade = this.sDenom.copy(); + if(this.sDenomDeg>0 && this.sPoles!=null){ + this.sPolesPade = Complex.oneDarray(this.sDenomDeg); + for(int i=0; i<this.sDenomDeg; i++)this.sPolesPade[i] = this.sPoles[i].copy(); + } + this.zeroPoleCancellation(); + this.padeAdded = true; + + } + + // Get the Pade approximation order + public int orderPade(){ + return this.orderPade; + } + + // Warning message if dead time greater than sampling period + protected boolean deadTimeWarning(String method){ + boolean warning = false; // warning true if dead time is greater than the sampling period + // false if not + if(this.deadTime>this.deltaT){ + System.out.println(this.name+"."+method+": The dead time is greater than the sampling period"); + System.out.println("Dead time: "+this.deadTime); + System.out.println("Sampling period: "+this.deltaT); + System.out.println("!!! The results of this program may not be physically meaningful !!!"); + warning = true; + } + return warning; + } + + // Perform z transform for a given delta T + // Uses maptozAdHoc in this class but may be overridden in a subclass + public void zTransform(double deltat){ + this.mapstozAdHoc(deltat); + } + + // Perform z transform using an already set delta T + // Uses maptozAdHoc in this class but may be overridden in a subclass + public void zTransform(){ + this.mapstozAdHoc(); + } + + // Map s-plane zeros and poles of the transfer function onto the z-plane using the ad-hoc method + // for a given sampling period. + // References: + // John Dorsey, Continuous and Discrete Control Systems, pp 490-491, McGraw Hill (2002) + // J R Leigh, Applied Digital Control, pp 78-80, Prentice-Hall (1985) + public void mapstozAdHoc(double deltaT){ + this.deltaT = deltaT; + this.mapstozAdHoc(); + } + + // Map s-plane zeros and poles of the transfer function onto the z-plane using the ad-hoc method + // for an already set sampling period. + // References: + // John Dorsey, Continuous and Discrete Control Systems, pp 490-491, McGraw Hill (2002) + // J R Leigh, Applied Digital Control, pp 78-80, Prentice-Hall (1985) + public void mapstozAdHoc(){ + + this.deadTimeWarning("mapstozAdHoc"); + if(!this.padeAdded)this.transferPolesZeros(); + + // Calculate z-poles + this.zDenomDeg = this.sDenomDegPade; + ComplexPoly root = new ComplexPoly(1); + this.zDenom = new ComplexPoly(this.zDenomDeg); + if(zDenomDeg>0){ + this.zPoles = Complex.oneDarray(this.zDenomDeg); + for(int i=0; i<this.zDenomDeg; i++){ + zPoles[i]=Complex.exp(this.sPolesPade[i].times(this.deltaT)); + } + this.zDenom = ComplexPoly.rootsToPoly(zPoles); + } + + // Calculate z-zeros + // number of zeros from infinity poles + int infZeros = this.sDenomDegPade; + // check that total zeros does not exceed total poles + if(infZeros+this.sNumerDegPade>this.sDenomDegPade)infZeros=this.sDenomDegPade-this.sNumerDegPade; + // total number of zeros + this.zNumerDeg = this.sNumerDegPade + infZeros; + this.zNumer = new ComplexPoly(zNumerDeg); + this.zZeros = Complex.oneDarray(zNumerDeg); + // zero values + if(this.zNumerDeg>0){ + for(int i=0; i<this.sNumerDegPade; i++){ + zZeros[i]=Complex.exp(sZerosPade[i].times(this.deltaT)); + } + if(infZeros>0){ + if(maptozero){ + for(int i=this.sNumerDegPade; i<this.zNumerDeg; i++){ + zZeros[i]=Complex.zero(); + } + } + else{ + for(int i=this.sNumerDegPade; i<this.zNumerDeg; i++){ + zZeros[i]=Complex.minusOne(); + } + } + } + this.zNumer = ComplexPoly.rootsToPoly(this.zZeros); + } + + // Match s and z steady state gains + this.sValue=Complex.zero(); + this.zValue=Complex.plusOne(); + boolean testzeros = true; + while(testzeros){ + testzeros = false; + if(this.sDenomDegPade>0){ + for(int i=0; i<this.sDenomDegPade; i++){ + if(this.sPolesPade[i].truncate(3).equals(this.sValue.truncate(3)))testzeros=true; + } + } + if(!testzeros && this.sNumerDegPade>0){ + for(int i=0; i<this.sDenomDegPade; i++){ + if(this.sZerosPade[i].truncate(3).equals(this.sValue.truncate(3)))testzeros=true; + } + } + if(!testzeros && this.zDenomDeg>0){ + for(int i=0; i<this.zDenomDeg; i++){ + if(this.zPoles[i].truncate(3).equals(this.zValue.truncate(3)))testzeros=true; + } + } + if(!testzeros && this.zNumerDeg>0){ + for(int i=0; i<this.zDenomDeg; i++){ + if(this.zZeros[i].truncate(3).equals(this.zValue.truncate(3)))testzeros=true; + } + } + if(testzeros){ + this.sValue = this.sValue.plus(Complex.plusJay()).truncate(3); + this.zValue = Complex.exp(this.sValue.times(this.deltaT).truncate(3)); + } + } + Complex gs = this.evalTransFunctS(this.sValue); + Complex gz = this.evalTransFunctZ(this.zValue); + Complex constant = gs.over(gz); + ComplexPoly constantPoly = new ComplexPoly(constant); + this.zNumer = this.zNumer.times(constantPoly); + } + + // Set the map infinity zeros to zero or -1 option + // maptozero: if true infinity s zeros map to zero + // if false infinity s zeros map to minus one + // default value = false + public void setMaptozero(boolean maptozero){ + this.maptozero = maptozero; + } + + // Set the transfer function numerator in the z-domain + // Enter as an array of real (double) coefficients of the polynomial a + bs +c.s.s + d.s.s.s + .... + public void setZnumer(double[] coeff){ + this.zNumerDeg = coeff.length-1; + this.zNumer = new ComplexPoly(coeff); + this.zZeros = this.zNumer.rootsNoMessages(); + } + + // Set the transfer function numerator in the z-domain + // Enter as an array of Complex coefficients of the polynomial a + bs +c.s.s + d.s.s.s + .... + public void setZnumer(Complex[] coeff){ + this.zNumerDeg = coeff.length-1; + this.zNumer = new ComplexPoly(coeff); + this.zZeros = this.zNumer.rootsNoMessages(); + } + + // Set the transfer function numerator in the z-domain + // Enter as an existing instance of ComplexPoly + public void setZnumer(ComplexPoly coeff){ + this.zNumerDeg = coeff.getDeg(); + this.zNumer = ComplexPoly.copy(coeff); + this.zZeros = this.zNumer.rootsNoMessages(); + } + + // Set the transfer function denominator in the z-domain + // Enter as an array of real (double) coefficients of the polynomial a + bs +c.s.s + d.s.s.s + .... + public void setZdenom(double[] coeff){ + this.zDenomDeg = coeff.length-1; + this.zDenom = new ComplexPoly(coeff); + this.zPoles = this.zDenom.rootsNoMessages(); + } + + // Set the transfer function denomonatot in the z-domain + // Enter as an array of Complex coefficients of the polynomial a + bs +c.s.s + d.s.s.s + .... + public void setZdenom(Complex[] coeff){ + this.zDenomDeg = coeff.length-1; + this.zDenom = new ComplexPoly(coeff); + this.zPoles = this.zDenom.rootsNoMessages(); + } + + // Set the transfer function denominator in the z-domain + // Enter as an existing instance of ComplexPoly + public void setZdenom(ComplexPoly coeff){ + this.zDenomDeg = coeff.getDeg(); + this.zDenom = ComplexPoly.copy(coeff); + this.zPoles = this.zDenom.rootsNoMessages(); + } + + // Set the sampling period + public void setDeltaT(double deltaT ){ + this.deltaT=deltaT; + this.sampFreq=1.0D/this.deltaT; + this.deadTimeWarning("setDeltaT"); + } + + // Set the forgetting factor + public void setForgetFactor(double forget){ + this.forgetFactor = forget; + } + + // Set the sampling frequency + public void setSampFreq(double sfreq ){ + this.sampFreq=sfreq; + this.deltaT=1.0D/sampFreq; + this.deadTimeWarning("setSampFreq"); + } + + // Set the Laplacian s value (s - Complex) + public void setS(Complex s){ + this.sValue = Complex.copy(s); + } + + // Set the Laplacian s value (s - real + imaginary parts) + public void setS(double sr, double si){ + this.sValue.reset(sr,si); + } + + // Set the Laplacian s value (s - imag, real = 0.0) + public void setS(double si){ + this.sValue.reset(0.0D, si); + } + + // Set the z-transform z value (z - Complex) + public void setZ(Complex z){ + this.zValue = Complex.copy(z); + } + + // Set the z-transform z value (z - real + imaginary parts) + public void setZ(double zr, double zi){ + this.zValue.reset(zr,zi); + } + + // Set the z transform method + // 0 = s to z mapping (ad hoc procedure) + // 1 = specific z transform, e.g. z transform of a difference equation + public void setZtransformMethod(int ztransMethod){ + if(ztransMethod<0 || ztransMethod>1){ + System.out.println("z transform method option number " + ztransMethod + " not recognised"); + System.out.println("z tr methodansform option number set in BlackBox to the default value of 0 (s -> z ad hoc mapping)"); + this.integMethod = 0; + } + else{ + this.ztransMethod = ztransMethod; + } + } + + // Set the integration method [number option] + // 0 = trapezium, 1 = Backward rectangular, 2 = Foreward rectangular + public void setIntegrateOption(int integMethod){ + if(integMethod<0 || integMethod>2){ + System.out.println("integration method option number " + integMethod + " not recognised"); + System.out.println("integration method option number set in BlackBox to the default value of 0 (trapezium rule)"); + this.integMethod = 0; + } + else{ + this.integMethod = integMethod; + } + } + + // Set the integration method [String option] + // trapezium; trapezium, tutin. Backward rectangular; back backward. Foreward rectangular; foreward, fore + // Continuous time equivalent: continuous, cont + public void setIntegrateOption(String integMethodS){ + if(integMethodS.equals("trapezium") || integMethodS.equals("Trapezium") ||integMethodS.equals("tutin") || integMethodS.equals("Tutin")){ + this.integMethod = 0; + } + else{ + if(integMethodS.equals("backward") || integMethodS.equals("Backward") ||integMethodS.equals("back") || integMethodS.equals("Back")){ + this.integMethod = 1; + } + else{ + if(integMethodS.equals("foreward") || integMethodS.equals("Foreward") ||integMethodS.equals("fore") || integMethodS.equals("Fore")){ + this.integMethod = 2; + } + else{ + System.out.println("integration method option " + integMethodS + " not recognised"); + System.out.println("integration method option number set in PID to the default value of 0 (trapezium rule)"); + this.integMethod = 0; + } + } + } + } + + // Reset the length of the arrays storing the times, time domain inputs and time domain outputs + public void setSampleLength(int samplen){ + this.sampLen = samplen; + this.time = new double[samplen]; + this.inputT = new double[samplen]; + this.outputT = new double[samplen]; + } + + // Reset the name of the black box + public void setName(String name){ + this.name=name; + } + + // Enter current time domain time and input value + public void setInputT(double ttime, double inputt){ + for(int i=0; i<this.sampLen-2; i++){ + this.time[i]=this.time[i+1]; + this.inputT[i]=this.inputT[i+1]; + } + this.time[this.sampLen-1]=ttime; + this.inputT[this.sampLen-1]=inputt; + } + + // Reset s-domain input + public void setInputS(Complex input){ + this.inputS=input; + } + + // Reset all inputs, outputs and times to zero + public void resetZero(){ + for(int i=0; i<this.sampLen-1; i++){ + this.outputT[i] = 0.0D; + this.inputT[i] = 0.0D; + this.time[i] = 0.0D; + } + this.outputS = Complex.zero(); + this.inputS = Complex.zero(); + } + + // Calculate the zeros and poles in the s-domain + // does not include Pade approximation term + protected void calcPolesZerosS(){ + + if(this.sNumer!=null){ + if(this.sNumer.getDeg()>0)this.sZeros = this.sNumer.rootsNoMessages(); + if(this.sZeros!=null){ + this.sNumerScaleFactor = BlackBox.scaleFactor(this.sNumer, this.sZeros); + } + else{ + this.sNumerScaleFactor = this.sNumer.coeffCopy(0); + } + } + if(this.sDenom!=null){ + if(this.sDenom.getDeg()>0)this.sPoles = this.sDenom.rootsNoMessages(); + if(this.sPoles!=null){ + this.sDenomScaleFactor = BlackBox.scaleFactor(this.sDenom, this.sPoles); + } + else{ + this.sDenomScaleFactor = this.sDenom.coeffCopy(0); + } + } + + if(this.sNumerPade!=null){ + if(this.sNumerPade.getDeg()>0)this.sZerosPade = this.sNumerPade.rootsNoMessages(); + } + if(this.sDenomPade!=null){ + if(this.sDenomPade.getDeg()>0)this.sPolesPade = this.sDenomPade.rootsNoMessages(); + } + } + + // Eliminates identical poles and zeros in the s-domain + protected void zeroPoleCancellation(){ + boolean check = false; + boolean testI = true; + boolean testJ = true; + int i=0; + int j=0; + + if(this.sNumerDegPade==0 || this.sDenomDegPade==0)testI=false; + if(this.sZerosPade==null || this.sPolesPade==null)testI=false; + while(testI){ + j=0; + while(testJ){ + if(this.sZerosPade[i].isEqual(this.sPolesPade[j])){ + for(int k=j+1; k<this.sDenomDegPade; k++)this.sPolesPade[k-1] = this.sPolesPade[k].copy(); + this.sDenomDegPade--; + for(int k=i+1; k<this.sNumerDegPade; k++)this.sZerosPade[k-1] = this.sZerosPade[k].copy(); + this.sNumerDegPade--; + check = true; + testJ=false; + i--; + } + else{ + j++; + if(j>this.sDenomDegPade-1)testJ=false; + } + } + i++; + if(i>this.sNumerDegPade-1)testI=false; + } + if(check){ + if(this.sNumerDegPade==0){ + this.sNumerPade = new ComplexPoly(1.0D); + } + else{ + Complex[] holdn = Complex.oneDarray(sNumerDegPade); + for(int ii=0; ii<sNumerDegPade; ii++)holdn[i] = this.sZerosPade[ii].copy(); + this.sZerosPade = holdn; + this.sNumerPade = ComplexPoly.rootsToPoly(this.sZerosPade); + } + if(this.sDenomDegPade==0){ + this.sDenomPade = new ComplexPoly(1.0D); + } + else{ + Complex[] holdd = Complex.oneDarray(sDenomDegPade); + for(int ii=0; ii<sDenomDegPade; ii++)holdd[i] = this.sPolesPade[ii].copy(); + this.sPolesPade = holdd; + this.sDenomPade = ComplexPoly.rootsToPoly(this.sPolesPade); + } + } + + check = false; + testI = true; + testJ = true; + i=0; + j=0; + + if(this.sNumerDeg==0 || this.sDenomDeg==0)testI=false; + if(this.sZeros==null || this.sPoles==null)testI=false; + while(testI){ + j=0; + while(testJ){ + if(this.sZeros[i].isEqual(this.sPoles[j])){ + for(int k=j+1; k<this.sDenomDeg; k++)this.sPoles[k-1] = this.sPoles[k].copy(); + this.sDenomDeg--; + for(int k=i+1; k<this.sNumerDeg; k++)this.sZeros[k-1] = this.sZeros[k].copy(); + this.sNumerDeg--; + check = true; + testJ=false; + i--; + } + else{ + j++; + if(j>this.sDenomDeg-1)testJ=false; + } + } + i++; + if(i>this.sNumerDeg-1)testI=false; + } + if(check){ + if(this.sNumerDeg==0){ + this.sNumer = new ComplexPoly(1.0D); + } + else{ + Complex[] holdn = Complex.oneDarray(sNumerDeg); + for(int ii=0; ii<sNumerDeg; ii++)holdn[i] = this.sZeros[ii].copy(); + this.sZeros = holdn; + this.sNumer = ComplexPoly.rootsToPoly(this.sZeros); + this.sNumerWorkingFactor = this.sNumerScaleFactor; + } + if(this.sDenomDeg==0){ + this.sDenom = new ComplexPoly(1.0D); + } + else{ + Complex[] holdd = Complex.oneDarray(sDenomDeg); + for(int ii=0; ii<sDenomDeg; ii++)holdd[i] = this.sPoles[ii].copy(); + this.sPoles = holdd; + this.sDenom = ComplexPoly.rootsToPoly(this.sPoles); + this.sDenomWorkingFactor = this.sDenomScaleFactor; + } + } + } + + // Get steadty state value for a unit step input + public double getSeadyStateValue(){ + Complex num = this.sNumer.evaluate(Complex.zero()); + Complex den = this.sDenom.evaluate(Complex.zero()); + Complex ssc = num.over(den); + double ssdr = ssc.getReal(); + double ssdi = ssc.getImag(); + if(Math.abs(ssdi)>Math.abs(ssdr)*0.01){ + System.out.println("method getSteadyStateValue: The imaginary part, " + ssdi + ", is greater than 1 per cent of the the real part, " + ssdr); + System.out.println("Magnitude has been returned"); + } + return ssc.abs(); + } + + // Get steadty state value for a step input of magnitude, mag + public double getSeadyStateValue(double mag){ + Complex num = this.sNumer.evaluate(Complex.zero()); + Complex den = this.sDenom.evaluate(Complex.zero()); + Complex ssc = num.over(den); + double ssdr = ssc.getReal(); + double ssdi = ssc.getImag(); + if(Math.abs(ssdi)>Math.abs(ssdr)*0.01){ + System.out.println("method getSteadyStateValue: The imaginary part, " + ssdi + ", is greater than 1 per cent of the the real part, " + ssdr); + System.out.println("Magnitude has been returned"); + } + return mag*ssc.abs(); + } + + + + // Evaluate the s-domain tranfer function for the present value of s + // deadtime evaluated as exponential term + public Complex evalTransFunctS(){ + if(!this.padeAdded)this.transferPolesZeros(); + Complex num = this.sNumer.evaluate(this.sValue); + Complex den = this.sDenom.evaluate(this.sValue); + Complex lagterm = Complex.plusOne(); + if(this.deadTime!=0)lagterm = Complex.exp(this.sValue.times(-this.deadTime)); + return num.over(den).times(lagterm); + } + + // Evaluate the s-domain tranfer function for a given Complex value of s + public Complex evalTransFunctS(Complex sValue){ + if(!this.padeAdded)this.transferPolesZeros(); + this.sValue = Complex.copy(sValue); + Complex num = this.sNumer.evaluate(sValue); + Complex den = this.sDenom.evaluate(sValue); + Complex lagterm = Complex.plusOne(); + if(this.deadTime!=0)lagterm = Complex.exp(this.sValue.times(-this.deadTime)); + return num.over(den).times(lagterm); + } + + // Evaluate the s-domain tranfer function for a sine wave input at a given frequency (s^-1) + public Complex evalTransFunctS(double freq){ + if(!this.padeAdded)this.transferPolesZeros(); + this.sValue.reset(0.0D, 2.0D*Math.PI*freq); + Complex num = this.sNumer.evaluate(this.sValue); + Complex den = this.sDenom.evaluate(this.sValue); + Complex lagterm = Complex.plusOne(); + if(this.deadTime!=0)lagterm = Complex.exp(this.sValue.times(-this.deadTime)); + return num.over(den).times(lagterm); + } + + // Evaluate the magnitude of the s-domain tranfer function for the present value of s + public double evalMagTransFunctS(){ + if(!this.padeAdded)this.transferPolesZeros(); + Complex num = this.sNumer.evaluate(this.sValue); + Complex den = this.sDenom.evaluate(this.sValue); + Complex lagterm = Complex.plusOne(); + if(this.deadTime!=0)lagterm = Complex.exp(this.sValue.times(-this.deadTime)); + return (num.over(den).times(lagterm)).abs(); + } + + // Evaluate the magnitude of the s-domain tranfer function for a given Complex value of s + public double evalMagTransFunctS(Complex sValue){ + if(!this.padeAdded)this.transferPolesZeros(); + this.sValue = Complex.copy(sValue); + Complex num = this.sNumer.evaluate(sValue); + Complex den = this.sDenom.evaluate(sValue); + Complex lagterm = Complex.plusOne(); + if(this.deadTime!=0)lagterm = Complex.exp(this.sValue.times(-this.deadTime)); + return (num.over(den).times(lagterm)).abs(); + } + + // Evaluate the magnitude of the s-domain tranfer function for a sine wave input at a given frequency (s^-1) + public double evalMagTransFunctS(double freq){ + if(!this.padeAdded)this.transferPolesZeros(); + this.sValue.reset(0.0D, 2.0D*Math.PI*freq); + Complex num = this.sNumer.evaluate(this.sValue); + Complex den = this.sDenom.evaluate(this.sValue); + Complex lagterm = Complex.plusOne(); + if(this.deadTime!=0)lagterm = Complex.exp(this.sValue.times(-this.deadTime)); + return (num.over(den).times(lagterm)).abs(); + } + + // Evaluate the phase of the s-domain tranfer function for the present value of s + public double evalPhaseTransFunctS(){ + if(!this.padeAdded)this.transferPolesZeros(); + Complex num = this.sNumer.evaluate(this.sValue); + Complex den = this.sDenom.evaluate(this.sValue); + Complex lagterm = Complex.plusOne(); + if(this.deadTime!=0)lagterm = Complex.exp(this.sValue.times(-this.deadTime)); + return (num.over(den).times(lagterm)).arg(); + } + + // Evaluate the phase of the s-domain tranfer function for a given Complex value of s + public double evalPhaseTransFunctS(Complex sValue){ + if(!this.padeAdded)this.transferPolesZeros(); + this.sValue = Complex.copy(sValue); + Complex num = this.sNumer.evaluate(sValue); + Complex den = this.sDenom.evaluate(sValue); + Complex lagterm = Complex.plusOne(); + if(this.deadTime!=0)lagterm = Complex.exp(this.sValue.times(-this.deadTime)); + return (num.over(den).times(lagterm)).arg(); + } + + // Evaluate the phase of the s-domain tranfer function for a sine wave input at a given frequency (s^-1) + public double evalPhaseTransFunctS(double freq){ + if(!this.padeAdded)this.transferPolesZeros(); + this.sValue.reset(0.0D, 2.0D*Math.PI*freq); + Complex num = this.sNumer.evaluate(this.sValue); + Complex den = this.sDenom.evaluate(this.sValue); + Complex lagterm = Complex.plusOne(); + if(this.deadTime!=0)lagterm = Complex.exp(this.sValue.times(-this.deadTime)); + return (num.over(den).times(lagterm)).arg(); + } + + // Evaluate the z-domain tranfer function for the present value of z + public Complex evalTransFunctZ(){ + Complex num = this.zNumer.evaluate(this.zValue); + Complex den = this.zDenom.evaluate(this.zValue); + return num.over(den); + } + + // Evaluate the z-domain tranfer function for a given Complex value of z + public Complex evalTransFunctZ(Complex zValue){ + this.zValue = Complex.copy(zValue); + Complex num = this.zNumer.evaluate(zValue); + Complex den = this.zDenom.evaluate(zValue); + return num.over(den); + } + + // Evaluate the magnitude of the z-domain tranfer function for the present value of z + public double evalMagTransFunctZ(){ + Complex num = this.zNumer.evaluate(this.zValue); + Complex den = this.zDenom.evaluate(this.zValue); + return num.over(den).abs(); + } + + // Evaluate the magnitude of the z-domain tranfer function for a given Complex value of z + public double evalMagTransFunctZ(Complex zValue){ + this.zValue = Complex.copy(zValue); + Complex num = this.zNumer.evaluate(zValue); + Complex den = this.zDenom.evaluate(zValue); + return num.over(den).abs(); + } + + // Evaluate the phase of the z-domain tranfer function for the present value of z + public double evalPhaseTransFunctZ(){ + Complex num = this.zNumer.evaluate(this.zValue); + Complex den = this.zDenom.evaluate(this.zValue); + return num.over(den).arg(); + } + + // Evaluate the phase of the z-domain tranfer function for a given Complex value of z + public double evalPhaseTransFunctZ(Complex zValue){ + this.zValue = Complex.copy(zValue); + Complex num = this.zNumer.evaluate(zValue); + Complex den = this.zDenom.evaluate(zValue); + return num.over(den).arg(); + } + + // Get the integration method option + public int getIntegMethod(){ + return this.integMethod; + } + + // Get the z transform method option + public int getZtransformMethod(){ + return this.ztransMethod; + } + + // Get the length of the time, input (time domain) and output (time domain) arrays + public int getSampleLength(){ + return this.sampLen; + } + + // Get the forgetting factor + public double getForgetFactor(){ + return this.forgetFactor; + } + + // Get the current time + public double getCurrentTime(){ + return this.time[this.sampLen-1]; + } + + // Get the time array + public double[] getTime(){ + return this.time; + } + + // Get the current time domain input + public double getCurrentInputT(){ + return this.inputT[this.sampLen-1]; + } + + // Get the time domain input array + public double[] getInputT(){ + return this.inputT; + } + + // Get the s-domain input + public Complex getInputS(){ + return this.inputS; + } + + // Get the sampling period + public double getDeltaT(){ + return this.deltaT; + } + + // Get the sampling frequency + public double getSampFreq(){ + return this.sampFreq; + } + + // Get the Laplacian s value + public Complex getS(){ + return this.sValue; + } + + // Get the z-transform z value + public Complex getZ(){ + return this.zValue; + } + + // Get the degree of the original s-domain numerator polynomial + public int getSnumerDeg(){ + return this.sNumerDeg; + } + + // Get the degree of the s-domain numerator polynomial after any dead time Pade approximation added + public int getSnumerPadeDeg(){ + return this.sNumerDegPade; + } + + // Get the degree of the original s-domain denominator polynomial + public int getSdenomDeg(){ + return this.sDenomDeg; + } + + // Get the degree of the s-domain denominator polynomial after any dead time Pade approximation added + public int getSdenomPadeDeg(){ + return this.sDenomDegPade; + } + + // Get the original s-domain numerator polynomial + public ComplexPoly getSnumer(){ + return this.sNumer.times(this.sNumerWorkingFactor); + } + + // Get the s-domain numerator polynomial after any dead time Pade approximation added + public ComplexPoly getSnumerPade(){ + return this.sNumerPade.times(this.sNumerWorkingFactor); + } + + // Get the original s-domain denominator polynomial + public ComplexPoly getSdenom(){ + return this.sDenom.times(this.sDenomWorkingFactor); + } + + // Get the s-domain denominator polynomial after any dead time Pade approximation added + public ComplexPoly getSdenomPade(){ + return this.sDenomPade.times(this.sDenomWorkingFactor); + } + + // Get the degree of the z-domain numerator polynomial + public int getZnumerDeg(){ + return this.zNumerDeg; + } + + // Get the degree of the z-domain denominator polynomial + public int getZdenomDeg(){ + return this.zDenomDeg; + } + + // Get the z-domain numerator polynomial + public ComplexPoly getZnumer(){ + return this.zNumer; + } + + // Get the z-domain denominator polynomial + public ComplexPoly getZdenom(){ + return this.zDenom; + } + + // Get the s-domain zeros without any Pade zeros + public Complex[] getZerosS(){ + if(this.sZeros==null)this.calcPolesZerosS(); + if(this.sZeros==null){ + System.out.println("Method BlackBox.getZerosS:"); + System.out.println("There are either no s-domain zeros for this transfer function"); + System.out.println("or the s-domain numerator polynomial has not been set"); + System.out.println("null returned"); + return null; + } + else{ + return this.sZeros; + } + + } + + // Get the s-domain zeros plusany Pade zeros + public Complex[] getZerosPadeS(){ + if(this.sZeros==null)this.calcPolesZerosS(); + if(!this.padeAdded)this.transferPolesZeros(); + if(this.sZerosPade==null){ + System.out.println("Method BlackBox.getZerosPadeS:"); + System.out.println("There are either no s-domain zeros for this transfer function"); + System.out.println("or the s-domain numerator polynomial has not been set"); + System.out.println("null returned"); + return null; + } + else{ + return this.sZerosPade; + } + } + + // Get the s-domain poles without any Pade poles + public Complex[] getPolesS(){ + if(this.sPoles==null)this.calcPolesZerosS(); + if(this.sPoles==null){ + System.out.println("Method BlackBox.getPolesS:"); + System.out.println("There are either no s-domain poles for this transfer function"); + System.out.println("or the s-domain denominator polynomial has not been set"); + System.out.println("null returned"); + return null; + } + else{ + return this.sPoles; + } + } + + // Get the s-domain poles plus any Pade poles + public Complex[] getPolesPadeS(){ + if(this.sPoles==null)this.calcPolesZerosS(); + if(!this.padeAdded)this.transferPolesZeros(); + if(this.sPolesPade==null){ + System.out.println("Method BlackBox.getPolesPadeS:"); + System.out.println("There are either no s-domain poles for this transfer function"); + System.out.println("or the s-domain denominator polynomial has not been set"); + System.out.println("null returned"); + return null; + } + else{ + return this.sPolesPade; + } + } + + + // Get the z-domain zeros + public Complex[] getZerosZ(){ + if(this.zZeros==null){ + System.out.println("Method BlackBox.getZerosZ:"); + System.out.println("There are either no z-domain zeros for this transfer function"); + System.out.println("or the z-domain numerator polynomial has not been set"); + System.out.println("null returned"); + return null; + } + else{ + return this.zZeros; + } + } + + // Get the z-domain poles + public Complex[] getPolesZ(){ + if(this.zPoles==null){ + System.out.println("Method BlackBox.getPolesZ:"); + System.out.println("There are either no z-domain poles for this transfer function"); + System.out.println("or the z-domain denominator polynomial has not been set"); + System.out.println("null returned"); + return null; + } + else{ + return this.zPoles; + } + } + + // Get the map infinity zeros to zero or -1 option + // maptozero: if true infinity s zeros map to zero + // if false infinity s zeros map to minus one + public boolean getMaptozero(){ + return this.maptozero; + } + + // Get the name of the black box + public String getName(){ + return this.name; + } + + // Plot the poles and zeros of the BlackBox transfer function in the s-domain + // Excludes any Pade poles and zeros + public void plotPoleZeroS(){ + if(this.sNumer==null)throw new IllegalArgumentException("s domain numerator has not been set"); + if(this.sDenom==null)throw new IllegalArgumentException("s domain denominator has not been set"); + PlotPoleZero ppz = new PlotPoleZero(this.sNumer, this.sDenom); + ppz.setS(); + ppz.pzPlot(this.name); + } + + // Plot the poles and zeros of the BlackBox transfer function in the s-domain + // Includes Pade poles and zeros + public void plotPoleZeroPadeS(){ + if(!this.padeAdded)this.transferPolesZeros(); + if(this.sNumerPade==null)throw new IllegalArgumentException("s domain numerator has not been set"); + if(this.sDenomPade==null)throw new IllegalArgumentException("s domain denominator has not been set"); + PlotPoleZero ppz = new PlotPoleZero(this.sNumerPade, this.sDenomPade); + ppz.setS(); + ppz.pzPlot(this.name); + } + + // Plot the poles and zeros of the BlackBox transfer function in the z-domain + public void plotPoleZeroZ(){ + PlotPoleZero ppz = new PlotPoleZero(this.zNumer, this.zDenom); + if(this.zNumer==null)throw new IllegalArgumentException("z domain numerator has not been set"); + if(this.zDenom==null)throw new IllegalArgumentException("z domain denominator has not been set"); + ppz.setZ(); + ppz.pzPlot(this.name); + } + + // Bode plots for the magnitude and phase of the s-domain transfer function + public void plotBode(double lowFreq, double highFreq){ + if(!this.padeAdded)this.transferPolesZeros(); + int nPoints = 100; + double[][] cdata = new double[2][nPoints]; + double[] logFreqArray = new double[nPoints+1]; + double logLow = Fmath.log10(2.0D*Math.PI*lowFreq); + double logHigh = Fmath.log10(2.0D*Math.PI*highFreq); + double incr = (logHigh - logLow)/((double)nPoints-1.0D); + double freqArray = lowFreq; + logFreqArray[0]=logLow; + for(int i=0; i<nPoints; i++){ + freqArray=Math.pow(10,logFreqArray[i]); + cdata[0][i]=logFreqArray[i]; + cdata[1][i]=20.0D*Fmath.log10(this.evalMagTransFunctS(freqArray/(2.0*Math.PI))); + logFreqArray[i+1]=logFreqArray[i]+incr; + } + + PlotGraph pgmag = new PlotGraph(cdata); + pgmag.setGraphTitle("Bode Plot = magnitude versus log10[radial frequency]"); + pgmag.setGraphTitle2(this.name); + pgmag.setXaxisLegend("Log10[radial frequency]"); + pgmag.setYaxisLegend("Magnitude[Transfer Function]"); + pgmag.setYaxisUnitsName("dB"); + pgmag.setPoint(0); + pgmag.setLine(3); + pgmag.plot(); + for(int i=0; i<nPoints; i++){ + freqArray=Math.pow(10,logFreqArray[i]); + cdata[0][i]=logFreqArray[i]; + cdata[1][i]=this.evalPhaseTransFunctS(freqArray)*180.0D/Math.PI; + } + PlotGraph pgphase = new PlotGraph(cdata); + pgphase.setGraphTitle("Bode Plot = phase versus log10[radial frequency]"); + pgphase.setGraphTitle2(this.name); + pgphase.setXaxisLegend("Log10[radial frequency]"); + pgphase.setYaxisLegend("Phase[Transfer Function]"); + pgphase.setYaxisUnitsName("degrees"); + pgphase.setPoint(0); + pgmag.setLine(3); + pgphase.plot(); + + } + + // Get the current time domain output for a given input and given time + // resets deltaT + public double getCurrentOutputT(double ttime, double inp){ + if(ttime<=time[this.sampLen-1])throw new IllegalArgumentException("Current time equals or is less than previous time"); + this.deltaT = ttime - this.time[this.sampLen-1]; + this.sampFreq = 1.0D/this.deltaT; + this.deadTimeWarning("getCurrentOutputT(time,input)"); + for(int i=0; i<this.sampLen-2; i++){ + this.time[i]=this.time[i+1]; + this.inputT[i]=this.inputT[i+1]; + } + this.time[this.sampLen-1]=ttime; + this.inputT[this.sampLen-1]=inp; + return this.getCurrentOutputT(); + } + + // Get the current time domain output for the stored input + public double getCurrentOutputT(){ + if(!this.padeAdded)this.transferPolesZeros(); + + Complex[][] coeffT = BlackBox.inverseTransform(this.sNumerPade, this.sDenomPade, this.sNumerWorkingFactor, this.sDenomScaleFactor); + Complex tempc = Complex.zero(); + for(int j=0; j<coeffT[0].length; j++){ + tempc.plusEquals(BlackBox.timeTerm(this.time[this.sampLen-1], coeffT[0][j], coeffT[1][j], coeffT[2][j])); + } + double outReal = tempc.getReal(); + double outImag = tempc.getImag(); + double temp; + boolean outTest=true; + if(outImag==0.0D)outTest=false; + if(outTest){ + temp=Math.max(Math.abs(outReal),Math.abs(outImag)); + if(Math.abs((outReal-outImag)/temp)>1.e-5){ + outTest=false; + } + else{ + System.out.println("output in Blackbox.getCurrentOutputT() has a significant imaginary part"); + System.out.println("time = " + this.time[this.sampLen-1] + " real = " + outReal + " imag = " + outImag); + System.out.println("Output equated to the real part"); + } + } + for(int i=0; i<this.sampLen-2; i++)this.outputT[i]=this.outputT[i+1]; + this.outputT[this.sampLen-1] = outReal*this.inputT[this.sampLen-1]; + return this.outputT[this.sampLen-1]; + } + + // Get the time domain output array + public double[] getOutputT(){ + return this.outputT; + } + + // Get the s-domain output for the stored input and s value. + public Complex getOutputS(){ + if(!this.padeAdded)this.transferPolesZeros(); + Complex num = this.sNumer.evaluate(this.sValue); + Complex den = this.sDenom.evaluate(this.sValue); + this.outputS = num.over(den).times(this.inputS); + if(this.deadTime!=0)this.outputS = this.outputS.times(Complex.exp(this.sValue.times(-this.deadTime))); + return this.outputS; + } + + // Get the s-domain output for a given s value and input. + public Complex getOutputS(Complex svalue, Complex inputs){ + if(!this.padeAdded)this.transferPolesZeros(); + this.inputS = inputs; + this.sValue = svalue; + Complex num = this.sNumer.evaluate(this.sValue); + Complex den = this.sDenom.evaluate(this.sValue); + this.outputS = num.over(den).times(this.inputS); + if(this.deadTime!=0)this.outputS = this.outputS.times(Complex.exp(this.sValue.times(-this.deadTime))); + return this.outputS; + } + + // Reset the number of points used in plotting a response curve + public void setNplotPoints(int nPoints){ + this.nPlotPoints = nPoints; + } + + // Return the number of points used in plotting a response curve + public int getNplotPoints(){ + return this.nPlotPoints; + } + + // Plots the time course for an impulse input + public void impulseInput(double impulseMag, double finalTime){ + if(!this.padeAdded)this.transferPolesZeros(); + + // Multiply transfer function by impulse magnitude (impulseMag) + ComplexPoly impulseN = new ComplexPoly(0); + impulseN.resetCoeff(0, Complex.plusOne().times(impulseMag)); + ComplexPoly numerT = this.sNumerPade.times(impulseN); + ComplexPoly denomT = this.sDenomPade.copy(); + String graphtitle1 = "Impulse Input Transient: Impulse magnitude = "+impulseMag; + String graphtitle2 = this.getName(); + BlackBox.transientResponse(this.nPlotPoints, finalTime, this.deadTime, numerT, denomT, graphtitle1, graphtitle2, this.sNumerWorkingFactor, this.sDenomScaleFactor); + } + + // Plots the time course for a unit impulse input + public void impulseInput(double finalTime){ + this.impulseInput(1.0D, finalTime); + } + + // Plots the time course for a step input + public void stepInput(double stepMag, double finalTime){ + Complex sNumer0 = this.sNumerPade.coeffCopy(0); + Complex sDenom0 = this.sDenomPade.coeffCopy(0); + boolean test0 = false; + if(Complex.isReal(sNumer0) && Complex.isReal(sDenom0))test0=true; + + if(sNumerDeg==0 && sDenomDeg==0 && test0){ + // Calculate time course outputs + int n = 51; // number of points on plot + double incrT = finalTime/(double)(n-2); // plotting increment + double cdata[][] = new double [2][n]; // plotting array + + cdata[0][0]=0.0D; + cdata[0][1]=0.0D; + for(int i=2; i<n; i++){ + cdata[0][i]=cdata[0][i-1]+incrT; + } + double kpterm = sNumer0.getReal()*stepMag/sDenom0.getReal(); + cdata[1][0]=0.0D; + for(int i=1; i<n; i++){ + cdata[1][i] = kpterm; + } + if(this.deadTime!=0.0D)for(int i=0; i<n; i++)cdata[0][i] += this.deadTime; + + // Plot + PlotGraph pg = new PlotGraph(cdata); + + pg.setGraphTitle("Step Input Transient: Step magnitude = "+stepMag); + pg.setGraphTitle2(this.getName()); + pg.setXaxisLegend("Time"); + pg.setXaxisUnitsName("s"); + pg.setYaxisLegend("Output"); + pg.setPoint(0); + pg.setLine(3); + pg.plot(); + + } + else{ + if(!this.padeAdded)this.transferPolesZeros(); + // Multiply transfer function by step magnitude (stepMag)/s + ComplexPoly numerT = this.sNumer.times(stepMag); + Complex[] polyC = {Complex.zero(), Complex.plusOne()}; + ComplexPoly polyH = new ComplexPoly(polyC); + ComplexPoly denomT = this.sDenom.times(polyH); + String graphtitle1 = "Step Input Transient: Step magnitude = "+stepMag; + String graphtitle2 = this.getName(); + + BlackBox.transientResponse(this.nPlotPoints, finalTime, this.deadTime, numerT, denomT, graphtitle1, graphtitle2, this.sNumerWorkingFactor, this.sDenomScaleFactor); + } + } + + // Plots the time course for a unit step input + public void stepInput(double finalTime){ + this.stepInput(1.0D, finalTime); + } + + // Plots the time course for an nth order ramp input (a.t^n) + public void rampInput(double rampGradient, int rampOrder, double finalTime){ + if(!this.padeAdded)this.transferPolesZeros(); + + // Multiply transfer function by ramp input (rampGradient)(rampOrder!)/s^(ramporder+1) + ComplexPoly numerT = this.sNumer.times(rampGradient*Fmath.factorial(rampOrder)); + Complex[] polyC = Complex.oneDarray(rampOrder+1); + for(int i=0; i<rampOrder; i++)polyC[i] = Complex.zero(); + polyC[rampOrder] = Complex.plusOne(); + ComplexPoly polyH = new ComplexPoly(polyC); + ComplexPoly denomT = this.sDenom.times(polyH); + String graphtitle1 = ""; + if(rampGradient!=1.0D){ + if(rampOrder!=1){ + graphtitle1 += "nth order ramp (at^n) input transient: a = "+rampGradient+" n = "+rampOrder; + } + else{ + graphtitle1 += "First order ramp (at) input transient: a = "+rampGradient; + } + } + else{ + if(rampOrder!=1){ + graphtitle1 += "Unit ramp (t) input transient"; + } + else{ + graphtitle1 += "nth order ramp (t^n) input transient: n = "+rampOrder; + } + } + String graphtitle2 = this.getName(); + BlackBox.transientResponse(this.nPlotPoints, finalTime, this.deadTime, numerT, denomT, graphtitle1, graphtitle2, this.sNumerWorkingFactor, this.sDenomScaleFactor); + } + + // Plots the time course for an nth order ramp input (t^n) + public void rampInput(int rampOrder, double finalTime){ + double rampGradient = 1.0D; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Plots the time course for a first order ramp input (at) + public void rampInput(double rampGradient, double finalTime){ + int rampOrder = 1; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Plots the time course for a unit ramp input (t) + public void rampInput(double finalTime){ + double rampGradient = 1.0D; + int rampOrder = 1; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Plots the time course for a given transfer function from time t = zero for a quiescent system + // Denominator scaling factor calculated + public static void transientResponse(int nPoints, double finalTime, double deadTime, ComplexPoly numerT, ComplexPoly denomT, String graphtitle1, String graphtitle2){ + Complex[] roots = denomT.rootsNoMessages(); + Complex magDenom = BlackBox.scaleFactor(denomT, roots); + Complex magNumer = Complex.plusOne(); + BlackBox.transientResponse(nPoints, finalTime, deadTime, numerT, denomT, graphtitle1, graphtitle2, magNumer, magDenom); + } + + // Plots the time course for a given transfer function from time t = zero for a quiescent system + // Denominator scaling factor provided + public static void transientResponse(int nPoints, double finalTime, double deadTime, ComplexPoly numerT, ComplexPoly denomT, String graphtitle1, String graphtitle2, Complex magN, Complex magD){ + // Obtain coefficients and constants of an partial fraction expansion + + + Complex[][] coeffT = BlackBox.inverseTransform(numerT, denomT, magN, magD); + + // Calculate time course outputs + int m = denomT.getDeg(); // number of Aexp(-at) terms + double incrT = finalTime/(double)(nPoints-1); // plotting increment + double cdata[][] = new double [2][nPoints]; // plotting array + double temp = 0.0D; // working variable + Complex tempc = new Complex(); // working variable + double outReal = 0.0D; // real part of output + double outImag = 0.0D; // imaginary part of output (should be zero) + boolean outTest = true; // false if outImag=zero + + cdata[0][0]=0.0D; + for(int i=1; i<nPoints; i++){ + cdata[0][i]=cdata[0][i-1]+incrT; + } + for(int i=0; i<nPoints; i++){ + outTest= true; + tempc = Complex.zero(); + for(int j=0; j<m; j++){ + tempc.plusEquals(BlackBox.timeTerm(cdata[0][i], coeffT[0][j], coeffT[1][j], coeffT[2][j])); + } + outReal = tempc.getReal(); + outImag = tempc.getImag(); + if(outImag==0.0D)outTest=false; + if(outTest){ + temp=Math.max(Math.abs(outReal),Math.abs(outImag)); + if(Math.abs((outReal-outImag)/temp)>1.e-5){ + outTest=false; + } + else{ + System.out.println("output in Blackbox.stepInput has a significant imaginary part"); + System.out.println("time = " + cdata[0][i] + " real = " + outReal + " imag = " + outImag); + System.out.println("Output equated to the real part"); + } + } + cdata[1][i]=outReal; + cdata[0][i]+=deadTime; + } + + // Plot + PlotGraph pg = new PlotGraph(cdata); + + pg.setGraphTitle(graphtitle1); + pg.setGraphTitle2(graphtitle2); + pg.setXaxisLegend("Time"); + pg.setXaxisUnitsName("s"); + pg.setYaxisLegend("Output"); + pg.setPoint(0); + pg.setLine(3); + pg.setNoYoffset(true); + if(deadTime<(cdata[0][nPoints-1]-cdata[0][0]))pg.setNoXoffset(true); + pg.setXlowFac(0.0D); + pg.setYlowFac(0.0D); + pg.plot(); + } + + + // Returns the output term for a given time, coefficient, constant and power + // for output = A.time^(n-1).exp(constant*time)/(n-1)! + public static Complex timeTerm(double ttime, Complex coeff, Complex constant, Complex power){ + Complex ret = new Complex(); + int n = (int)power.getReal() - 1; + ret = coeff.times(Math.pow(ttime,n)); + ret = ret.over(Fmath.factorial(n)); + ret = ret.times(Complex.exp(constant.times(ttime))); + return ret; + } + + // Returns the coefficients A, the constant a and the power n in the f(A.exp(-at),n) term for the + // the inverse Laplace transform of a complex polynolial divided + // by a complex polynomial expanded as partial fractions + // A and a are returnd as a 2 x n Complex array were n is the number of terms + // in the partial fraction. the first row contains the A values, the second the a values + // denominator scaling factor calculated + public static Complex[][] inverseTransform(ComplexPoly numer, ComplexPoly denom){ + Complex[] roots = denom.rootsNoMessages(); + Complex magDenom = BlackBox.scaleFactor(denom, roots); + Complex magNumer = Complex.plusOne(); + return inverseTransform(numer, denom, magNumer, magDenom); + } + + // Returns the coefficients A, the constant a and the power n in the f(A.exp(-at),n) term for the + // the inverse Laplace transform of a complex polynolial divided + // by a complex polynomial expanded as partial fractions + // A and a are returnd as a 2 x n Complex array were n is the number of terms + // in the partial fraction. the first row contains the A values, the second the a values + // denominator scaling factor provided + public static Complex[][] inverseTransform(ComplexPoly numer, ComplexPoly denom, Complex magNumer, Complex magDenom){ + + int polesN = denom.getDeg(); // number of poles + int zerosN = numer.getDeg(); // numer of zeros + if(zerosN>=polesN)throw new IllegalArgumentException("The degree of the numerator is equal to or greater than the degree of the denominator"); + Complex[][] ret = Complex.twoDarray(3, polesN); // array for returning coefficients, constants and powers + + // Special case: input = A/(B + C)s + if(polesN==1 && zerosN==0){ + Complex num = numer.coeffCopy(0); + Complex den0 = denom.coeffCopy(0); + Complex den1 = denom.coeffCopy(1); + ret[0][0] = num.over(den1); + ret[1][0] = Complex.minusOne().times(den0.over(den1)); + ret[2][0] = new Complex(1.0, 0.0); + return ret; + } + + int nDifferentRoots = polesN; // number of roots of different values + int nSetsIdenticalRoots = 0; // number of sets roots of identical value + Complex[] poles = denom.rootsNoMessages(); // poles array + int[] polePower = new int[polesN]; // power, n, of each (s - root)^n term + boolean[] poleSet = new boolean[polesN]; // true if root has been identified as either equal to another root + int[] poleIdent = new int[polesN]; // same integer for identical (s-root) terms; integer = index of first case of that root + int[] poleHighestPower = new int[polesN]; // highest pole power for that set of identical poles + boolean[] termSet = new boolean[polesN]; // false if n in (s-root)^n is greater than 1 and less than maximum value of n for that root + double identicalRootLimit = 1.0e-2; // roots treated as identical if equal to one part in identicalRootLimit + int[] numberInSet = new int[polesN]; // number of poles indentical to this pole including this pole + + // Find identical roots within identicalRootLimit and assign power n [ (s-a)^n] to all roots + int power = 0; + Complex identPoleAverage = new Complex(); + int lastPowerIndex=0; + for(int i=0; i<polesN; i++)poleSet[i]=false; + for(int i=0; i<polesN; i++)termSet[i]=true; + for(int i=0; i<polesN; i++){ + if(!poleSet[i]){ + power=1; + polePower[i]=1; + poleHighestPower[i]= 1; + poleIdent[i]=i; + numberInSet[i]=1; + identPoleAverage = poles[i]; + for(int j=i+1; j<polesN; j++){ + if(!poleSet[j]){ + if(poles[i].isEqualWithinLimits(poles[j],identicalRootLimit)){ + poleIdent[j]=i; + polePower[j]=++power; + poleSet[j]=true; + poleSet[i]=true; + termSet[j]=false; + termSet[i]=false; + lastPowerIndex=j; + nDifferentRoots--; + identPoleAverage = identPoleAverage.plus(poles[j]); + } + else{ + poleIdent[j]=j; + polePower[j]=1; + } + } + } + } + + if(poleSet[i]){ + nDifferentRoots--; + nSetsIdenticalRoots++; + + // Set termSet to true if pole is recurring term with the highest power + termSet[lastPowerIndex]=true; + + // Replace roots within identicalRootLimit with their average value + identPoleAverage = identPoleAverage.over(power); + for(int j=0; j<polesN; j++){ + if(poleSet[j] && poleIdent[j]==i){ + poles[j] = identPoleAverage; + poleHighestPower[i] = power; + numberInSet[j] = power; + } + } + } + } + + // Calculate pole average + Complex poleAverage = Complex.zero(); + Complex absPoleAverage = Complex.zero(); + for(int i=0; i<polesN; i++){ + poleAverage = poleAverage.plus(poles[i]); + absPoleAverage = absPoleAverage.plus(poles[i].abs()); + } + poleAverage = poleAverage.over(polesN); + absPoleAverage = absPoleAverage.over(polesN); + + // Calculate pole substitute for identical substitution values + Complex poleSubstitute = poleAverage; + if(poleSubstitute.isZero())poleSubstitute = absPoleAverage; + if(poleSubstitute.isZero())poleSubstitute = Complex.plusOne(); + + // Choose initial set of s substitution values + Complex[] subValues = Complex.oneDarray(polesN); + boolean[] subSet = new boolean[polesN]; + for(int i=0; i<polesN; i++)subSet[i] = false; + + Complex[] shifts = null; + Complex delta = new Complex(1.7, 0.0); // root separation factor + for(int i=0; i<polesN; i++)subValues[i] = poles[i].copy(); + int currentNumberInSet = 0; + if(nSetsIdenticalRoots>0){ + for(int i=0; i<polesN; i++){ + if(numberInSet[i]>1 && !subSet[i]){ + currentNumberInSet = numberInSet[i]; + shifts = Complex.oneDarray(numberInSet[i]); + int centre = numberInSet[i]/2; + if(Fmath.isEven(numberInSet[i])){ + for(int j=0; j<centre; j++){ + shifts[centre+j] = delta.times((double)(j+1)); + shifts[centre-1-j] = shifts[centre+j].times(-1.0); + } + } + else{ + shifts[centre] = Complex.zero(); + for(int j=0; j<centre; j++){ + shifts[centre+1+j] = delta.times((double)(j+1)); + shifts[centre-1-j] = shifts[centre+j].times(-1.0); + } + } + int kk = 0; + for(int j=0; j<polesN; j++){ + if(!subSet[j] && numberInSet[j]==currentNumberInSet){ + Complex incr = poles[j]; + if(incr.isZero())incr = poleSubstitute; + subValues[j] = shifts[kk].times(incr); + subSet[j] = true; + kk++; + + } + } + } + } + } + + // Check for identical and very close substitution values + boolean testii = true; + int ii = 0; + int nAttempts = 0; + while(testii){ + int jj = ii + 1; + boolean testjj = true; + while(testjj){ + if(subValues[ii].isEqualWithinLimits(subValues[jj],identicalRootLimit)){ + subValues[ii] = subValues[ii].plus(poleSubstitute.times((double)nAttempts)); + nAttempts++; + ii=0; + testjj = false; + if(nAttempts>1000000)throw new IllegalArgumentException("a non repeating set of substitution values could not be foumd"); + } + else{ + jj++; + } + if(jj>=polesN)testjj = false; + } + ii++; + if(ii>=polesN-1)testii = false; + } + + // Set up the linear equations + // Create vector and matrix arrays + Complex[][] mat = Complex.twoDarray(polesN, polesN); + Complex[] vec = Complex.oneDarray(polesN); + + // Fill vector + for(int i=0; i<polesN; i++){ + if(zerosN>0){ + vec[i] = numer.evaluate(subValues[i]); + } + else{ + vec[i] = numer.coeffCopy(0); + } + } + + // fill matrix + for(int i=0; i<polesN; i++){ + for(int j=0; j<polesN; j++){ + Complex denomTerm = Complex.plusOne(); + int powerD = 0; + for(int k=0; k<polesN; k++){ + if(termSet[k]){ + if(j!=k){ + if(polePower[k]==1){ + denomTerm = denomTerm.times(subValues[i].minus(poles[k])); + } + else{ + denomTerm = denomTerm.times(Complex.pow(subValues[i].minus(poles[k]), polePower[k])); + } + } + else{ + if(polePower[j]<poleHighestPower[j]){ + powerD = poleHighestPower[j] - polePower[j]; + if(powerD==1){ + denomTerm = denomTerm.times(subValues[i].minus(poles[k])); + } + else{ + if(powerD!=0){ + denomTerm = denomTerm.times(Complex.pow(subValues[i].minus(poles[k]), powerD)); + } + } + } + } + } + } + mat[i][j] = denomTerm; + } + + } + + + // Solve linear equations + ComplexMatrix cmat = new ComplexMatrix(mat); + Complex[] terms = cmat.solveLinearSet(vec); + + // fill ret for returning + for(int i=0; i<polesN; i++){ + ret[0][i]=terms[i].times(magNumer).over(magDenom); + ret[1][i]=poles[i]; + ret[2][i].reset(polePower[i],0.0D); + } + return ret; + + } + + // Deep copy + public BlackBox copy(){ + if(this==null){ + return null; + } + else{ + BlackBox bb = new BlackBox(); + this.copyBBvariables(bb); + return bb; + } + } + + // Copies BlackBox variables + public void copyBBvariables(BlackBox bb){ + + bb.sampLen = this.sampLen; + bb.inputT = this.inputT.clone(); + bb.outputT = this.outputT.clone(); + bb.time = this.time.clone(); + bb.forgetFactor = this.forgetFactor; + bb.deltaT = this.deltaT; + bb.sampFreq = this.sampFreq; + bb.inputS = this.inputS.copy(); + bb.outputS = this.outputS.copy(); + bb.sValue = this.sValue.copy(); + bb.zValue = this.zValue.copy(); + bb.sNumer = this.sNumer.copy(); + bb.sDenom = this.sDenom.copy(); + bb.zNumer = this.zNumer.copy(); + bb.zDenom = this.zDenom.copy(); + bb.sNumerSet = this.sNumerSet; + bb.sDenomSet = this.sDenomSet; + bb.sNumerScaleFactor = this.sNumerScaleFactor; + bb.sDenomScaleFactor = this.sDenomScaleFactor; + bb.sPoles = Complex.copy(this.sPoles); + bb.sZeros = Complex.copy(this.sZeros); + bb.zPoles = Complex.copy(this.zPoles); + bb.zZeros = Complex.copy(this.zZeros); + bb.sNumerDeg = this.sNumerDeg; + bb.sDenomDeg = this.sDenomDeg; + bb.zNumerDeg = this.zNumerDeg; + bb.zDenomDeg = this.zDenomDeg; + bb.deadTime = this.deadTime; + bb.orderPade = this.orderPade; + bb.sNumerPade = this.sNumerPade.copy(); + bb.sDenomPade = this.sDenomPade.copy(); + bb.sPolesPade = Complex.copy(this.sPolesPade); + bb.sZerosPade = Complex.copy(this.sZerosPade); + bb.sNumerDegPade = this.sNumerDegPade; + bb.sDenomDegPade = this.sDenomDegPade; + bb.maptozero = this.maptozero; + bb.padeAdded = this.padeAdded; + bb.integrationSum = this.integrationSum; + bb.integMethod = this.integMethod; + bb.ztransMethod = this.ztransMethod; + bb.name = this.name; + bb.fixedName = this.fixedName; + bb.nPlotPoints = this.nPlotPoints; + + } + + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} + diff --git a/src/main/java/flanagan/control/ClosedLoop.java b/src/main/java/flanagan/control/ClosedLoop.java new file mode 100755 index 0000000000000000000000000000000000000000..92df65419087707077f0fb0d48f79842de7d9b1f --- /dev/null +++ b/src/main/java/flanagan/control/ClosedLoop.java @@ -0,0 +1,215 @@ +/* Class ClosedLoop +* +* This class supports the creation of a path of Black Boxes +* i.e. of instances of BlackBox and of any of its subclasses, +* e.g. PropIntDeriv, FirstOrder, and the methods to combine +* these into both a single instance of BlackBox and a Vector +* of analogue segments, digital segments and converters, +* with a feedback path from the last box on the forward path to the first box on the forward path +* +* Author: Michael Thomas Flanagan. +* +* Created: August 2002 +* Updated: 14 May 2005, 6 April 2008, 5 July 2008, 2-7 November 2009 +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/OpenLoop.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* +* Copyright (c) 2002 - 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.control; + +import java.util.Vector; +import java.util.ArrayList; +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; +import flanagan.control.OpenLoop; + +public class ClosedLoop extends BlackBox{ + private OpenLoop forwardPath = new OpenLoop(); // forward path boxes + private OpenLoop closedPath = new OpenLoop(); // full closed path boxes + + private ArrayList<BlackBox> feedbackPath = new ArrayList<BlackBox>(); // feedback path boxes + private int nFeedbackBoxes = 0; // number of boxes in feedback path + + private boolean checkNoMix = true; // true - no ADC or DAC + private boolean checkConsolidate = false; // true if consolidate has been called + + private double deadTimeSum = 0.0; // dead time is replaced by Pade approximation to facilitate division + // sNumer and sDenom equated to sNumerPade and sDenomPade + // super.deadTime is replaced by zero + // true dead time stored in deadTimeSum which is returned by this classes getDeadTime method + + // Constructor + public ClosedLoop(){ + super("ClosedLoop"); + } + + // Add box to the forward path + public void addBoxToForwardPath(BlackBox box){ + this.forwardPath.addBoxToPath(box); + } + + // Add box to the open path + public void addBoxToFeedbackPath(BlackBox box){ + this.feedbackPath.add(box); + this.nFeedbackBoxes++; + } + + // Consolidate all boxes into appropriate segments and + // combine all boxes into either on forward path box or one closed loop box + public void consolidate(){ + + // add feedback boxes to forward path boxes + this.closedPath = this.forwardPath.copy(); + for(int i=0; i<this.nFeedbackBoxes; i++){ + this.closedPath.addBoxToPath(this.feedbackPath.get(i)); + } + + // combine forward path boxes + this.forwardPath.consolidate(); + if(!this.forwardPath.getCheckNoMix())this.checkNoMix = false; + + // combine closed path boxes + this.closedPath.consolidate(); + if(!this.closedPath.getCheckNoMix())this.checkNoMix = false; + + // Calculate transfer function + ComplexPoly fpNumer = this.forwardPath.getSnumer(); + ComplexPoly fpDenom = this.forwardPath.getSdenom(); + ComplexPoly cpNumer = this.closedPath.getSnumer(); + ComplexPoly cpDenom = this.closedPath.getSdenom(); + if(fpDenom.isEqual(cpDenom)){ + super.setSnumer(fpNumer.copy()); + super.setSdenom((cpNumer.plus(fpDenom)).copy()); + } + else{ + super.setSnumer(fpNumer.times(cpDenom)); + super.setSdenom((cpNumer.times(fpDenom)).plus(cpDenom.times(fpDenom))); + } + this.checkConsolidate = true; + this.deadTimeSum = this.closedPath.getDeadTime(); + super.deadTime = 0.0; + this.checkConsolidate = true; + } + + // Return number of boxes in the forward path + public int getNumberOfBoxesInForwardPath(){ + if(!checkConsolidate)this.consolidate(); + return this.forwardPath.getNumberOfBoxes(); + } + + // Return number of boxes in the closed path + public int getNumberOfBoxesInClosedLoop(){ + if(!checkConsolidate)this.consolidate(); + return this.closedPath.getNumberOfBoxes(); + } + + // Return segment ArrayList for forward path + public ArrayList<Object> getForwardPathSegmentsArrayList(){ + if(!checkConsolidate)this.consolidate(); + return this.forwardPath.getSegmentsArrayList(); + } + + // Return segment Vector for forward path + public Vector<Object> getForwardPathSegmentsVector(){ + if(!checkConsolidate)this.consolidate(); + return this.forwardPath.getSegmentsVector(); + } + + + // Return segment ArrayList for closed path + public ArrayList<Object> getClosedLoopSegmentsArrayList(){ + if(!checkConsolidate)this.consolidate(); + return this.closedPath.getSegmentsArrayList(); + } + + // Return segment Vector for closed path + public Vector<Object> getClosedLoopSegmentsVector(){ + if(!checkConsolidate)this.consolidate(); + return this.closedPath.getSegmentsVector(); + } + + // Return number of segments in the forward path + public int getNumberOfSegmentsInForwardPath(){ + if(!checkConsolidate)this.consolidate(); + return this.forwardPath.getNumberOfSegments(); + } + + // Return number of segments in the closed path + public int getNumberOfSegmentsInClosedLoop(){ + if(!checkConsolidate)this.consolidate(); + return this.closedPath.getNumberOfSegments(); + } + + // Return name of all boxes in forward path + public String getNamesOfBoxesInForwardPath(){ + if(!checkConsolidate)this.consolidate(); + return this.forwardPath.getNamesOfBoxes(); + } + + // Return name of all boxes in closed path + public String getNamesOfBoxesInClosedLoop(){ + if(!checkConsolidate)this.consolidate(); + return this.closedPath.getNamesOfBoxes(); + } + + // Remove all boxes from the path + public void removeAllBoxes(){ + this.forwardPath.removeAllBoxes(); + this.closedPath.removeAllBoxes(); + this.feedbackPath.clear(); + this.checkNoMix = true; + this.checkConsolidate = false; + this.nFeedbackBoxes = 0; + } + + // Get stored dead times + public double getDeadTime(){ + return this.deadTimeSum; + } + + // Deep copy + // Deep copy + public ClosedLoop copy(){ + if(this==null){ + return null; + } + else{ + ClosedLoop bb = new ClosedLoop(); + this.copyBBvariables(bb); + + bb.nFeedbackBoxes = this.nFeedbackBoxes; + bb.checkNoMix = this.checkNoMix; + bb.checkConsolidate = this.checkConsolidate; + bb.forwardPath = this.forwardPath.copy(); + bb.closedPath = this.closedPath.copy(); + bb.feedbackPath = new ArrayList<BlackBox>(); + if(this.feedbackPath.size()!=0){ + for(int i=0; i<feedbackPath.size(); i++)bb.feedbackPath.add((this.feedbackPath.get(i)).copy()); + } + + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/control/Compensator.java b/src/main/java/flanagan/control/Compensator.java new file mode 100755 index 0000000000000000000000000000000000000000..b4c2735781ad499c4e30888dc2d6ede86fb000aa --- /dev/null +++ b/src/main/java/flanagan/control/Compensator.java @@ -0,0 +1,162 @@ +/* Class Compensator +* +* This class contains the constructor to create an instance of +* a generalised compensator, +* K(a + s)/(b + s) +* and the methods needed to use this process in simulation +* of control loops. +* +* This class is a subclass of the superclass BlackBox. +* +* Author: Michael Thomas Flanagan. +* +* Created: 14 May 2005 +* Updates: 13 April 2006, 1 July 2006, 6 April 2008, 2 December 2008, 2-7 November 2009 +* +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Compensator.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.control; +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; + +public class Compensator extends BlackBox{ + + private double kConst = 1.0D; // K constant in compensator equation above + private double aConst = 1.0D; // a constant in compensator equation above + private double bConst = 1.0D; // b constant in compensator equation above + + // Constructor - all constants = 1 + public Compensator(){ + super("Compensator"); + super.sZeros = Complex.oneDarray(1); + super.sPoles = Complex.oneDarray(1); + super.setSnumer(new ComplexPoly(1.0D, 1.0D)); + super.setSdenom(new ComplexPoly(1.0D, 1.0D)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + } + + // Constructor + // constants set from argument list + public Compensator(double kk, double aa, double bb){ + super("Compensator"); + this.aConst = aa; + this.bConst = bb; + this.kConst = kk; + super.sZeros = Complex.oneDarray(1); + super.sPoles = Complex.oneDarray(1); + super.setSnumer(new ComplexPoly(this.aConst*kConst, kConst)); + super.setSdenom(new ComplexPoly(this.bConst, 1.0D)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + } + + public void setCoeff(double kk, double aa, double bb){ + this.aConst = aa; + this.bConst = bb; + this.kConst = kk; + Complex[] num = Complex.oneDarray(2); + num[0].reset(this.aConst*this.kConst, 0.0D); + num[1].reset(this.kConst, 0.0D); + super.sNumer.resetPoly(num); + Complex[] den = Complex.oneDarray(2); + den[0].reset(this.bConst, 0.0D); + den[1].reset(1.0D, 0.0D); + super.sDenom.resetPoly(den); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setK(double kk){ + this.kConst = kk; + Complex co = new Complex(this.aConst*this.kConst, 0.0); + super.sNumer.resetCoeff(0, co); + co = new Complex(this.kConst, 0.0); + super.sNumer.resetCoeff(1, co); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setA(double aa){ + this.aConst = aa; + Complex co = new Complex(this.aConst*this.kConst, 0.0); + super.sNumer.resetCoeff(0, co); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setB(double bb){ + this.bConst = bb; + Complex co = new Complex(this.bConst, 0.0); + super.sDenom.resetCoeff(0, co); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public double getA(){ + return this.aConst; + } + + public double getB(){ + return this.bConst; + } + + public double getK(){ + return this.kConst; + } + + // Calculate the zeros and poles in the s-domain + public void calcPolesZerosS(){ + super.sZeros[0].setReal(-aConst); + super.sPoles[0].setReal(-bConst); + super.sNumerScaleFactor = BlackBox.scaleFactor(super.sNumer, super.sZeros); + super.sDenomScaleFactor = BlackBox.scaleFactor(super.sDenom, super.sPoles); + + } + + // Deep copy + public Compensator copy(){ + if(this==null){ + return null; + } + else{ + Compensator bb = new Compensator(); + this.copyBBvariables(bb); + + bb.kConst = this.kConst; + bb.aConst = this.aConst; + bb.bConst = this.bConst; + + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/control/DelayLine.java b/src/main/java/flanagan/control/DelayLine.java new file mode 100755 index 0000000000000000000000000000000000000000..ed0bc9ac95cff598acc305a5879c798721d77fa1 --- /dev/null +++ b/src/main/java/flanagan/control/DelayLine.java @@ -0,0 +1,101 @@ +/* Class DelayLine +* +* This class contains the constructor to create an instance of +* a dead time delay, independently of any of the existing BlackBox +* subclasses or of the BlackBox superclass in which a dead time +* may be set, and the methods needed to use this delay in +* control loops in the time domain, Laplace transform s domain +* or the z-transform z domain. +* +* s-domain transfer function = exp(-Td.s) +* Td is the delay time. +* 1 to 4 order Pade approximations available +* +* This class is a subclass of the superclass BlackBox. +* +* Author: Michael Thomas Flanagan. +* +* Created: August 2002. +* Revised: 21 April 2003, 3 May 2005, 2 July 2006, 6 April 2008, 7 November 2009 +* +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/DelayLine.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + + + +package flanagan.control; + +import flanagan.complex.Complex; + +public class DelayLine extends BlackBox{ + + // Constructor + public DelayLine(double delayTime, int orderPade){ + super("DelayLine"); + super.setDeadTime(delayTime, orderPade); + } + + // Constructor + // Default Pade approximation order = 2 + public DelayLine(double delayTime){ + super("DelayLine"); + super.fixedName="DelayLine"; + super.setDeadTime(delayTime); + } + + // Constructor + // for deep copy purposes + private DelayLine(){ + super("DelayLine"); + } + + // Set the delay time + public void setDelayTime(double delayTime){ + super.setDeadTime(delayTime); + } + + // Set the delay time and the Pade approximation order + public void setDelayTime(double delayTime, int orderPade){ + super.setDeadTime(delayTime, orderPade); + } + + // Get the delay time + public double getDelayTime(){ + return super.deadTime; + } + + // Deep copy + public DelayLine copy(){ + if(this==null){ + return null; + } + else{ + DelayLine bb = new DelayLine(); + this.copyBBvariables(bb); + + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/control/DtoA.java b/src/main/java/flanagan/control/DtoA.java new file mode 100755 index 0000000000000000000000000000000000000000..5c347baee863cd3ecd4b4efb9c49e57f9511b067 --- /dev/null +++ b/src/main/java/flanagan/control/DtoA.java @@ -0,0 +1,394 @@ +/* Class DtoA +* +* This class contains constructor and methods that will +* 1. Simulate a Digital to Analogue Convertor (DAC) +* or +* 2. Simply act as a marker to be used in OpenPath and +* ClosedLoop to indicate the presence of an DAC. In the +* latter case the output is equal to the input plus any delay set. +* +* This class is a subclass of the superclass BlackBox. +* +* Author: Michael Thomas Flanagan. +* +* Created: 27 June 2003 +* Revised: 18 August 2003, 9 May 2005, April 2008, 7 November 2009 +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/DtoA.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.control; + +import flanagan.complex.*; + +public class DtoA extends BlackBox{ + + private int nBits = 0; // Number of bits, n + private long maximumDecimal = 0; // 2^n-1 + private double vRef = 0.0D; // Reference voltage + private int[] vBinary = null; // array holding binary input + private boolean trueDtoA = true; // if true, a real DAC is simulated + // if false, the instance is simply an DtoA marker + private double outputVoltage = 0.0D;// output voltage + private double voltageInput =0.0D; // input as voltage - if this is the input the output is put equal to this input + private String binaryInput = ""; // input as a binary String + private long decimalInput = 0L; // input as decimal representation of a binary String + private boolean inputSet = false; // = true when input is set + + // Constructor + // Simulates a DAC + public DtoA(int nBits, double vRef ){ + super("DtoA"); + super.setSnumer(new ComplexPoly(1.0D)); + super.setSdenom(new ComplexPoly(1.0D)); + super.setZtransformMethod(1); + this.nBits = nBits; + this.vBinary = new int[nBits+1]; + this.maximumDecimal = (long)Math.pow(2, this.nBits)-1L; + this.vRef = vRef; + this.trueDtoA = true; + } + + // Constructor + // Simply marks an DtoA event + public DtoA(){ + super("DtoA"); + this.trueDtoA = false; + super.sNumerDeg = 0; + super.sDenomDeg = 0; + super.setSnumer(new ComplexPoly(1.0D)); + super.setSdenom(new ComplexPoly(1.0D)); + super.setZtransformMethod(1); + } + + // Return the true DtoA option + public boolean getTrueDtoAoption(){ + if(this.trueDtoA){ + System.out.println("This instance of DtoA is a true simulation of an ADC"); + System.out.println("getTrueDtoAoption has returned 'true'"); + } + else{ + System.out.println("This instance of DtoA is not a true simulation of an ADC"); + System.out.println("It is simple an 'D to A marker'"); + System.out.println("getTrueDtoAoption has returned 'false'"); + } + return this.trueDtoA; + } + + // Set input entered as a Sting representing the binary inut in two's complement + // of n+1 bits where n = this.nBits and the extra bit is the sign bit + public void setInput(String input){ + this.binaryInput = input.trim(); + int len = this.binaryInput.length(); + if(len>this.nBits+1)throw new IllegalArgumentException("length of input String is greater than the DAC bit number plus one"); + if(len<this.nBits+1){ + System.out.println("Class - DtoA; method - setInput(String)"); + System.out.println("The input String is less than DAC number of bits plus one"); + System.out.println("String assumed to represent a postive unsigned binary number"); + System.out.println("unfilled bits assigned zeros"); + for(int i=len; i<this.nBits+1; i++)this.binaryInput = '0'+this.binaryInput; + len = this.nBits+1; + } + + // Convert String to int array + int ii = 0; + int jj = 0; + char c =' '; + for(int i=len-1; i>=0; i--){ + c = this.binaryInput.charAt(i); + if(c=='1'){ + ii=1; + } + else{ + if(c=='0'){ + ii = 0; + } + else{ + throw new IllegalArgumentException("String input must be '0's or '1's"); + } + } + jj = len-i-1; + this.vBinary[jj] = ii; + } + + // Check if input is negative + long sign = 1L; + int[] vPosBinary = this.vBinary.clone(); + if(this.vBinary[len-1]==1){ + sign = -1L; + vPosBinary = this.negateNegativeBinary(vPosBinary); + } + + // convert positive binary to decimal equivalent + this.decimalInput = DtoA.binaryToDecimal(vPosBinary); + + // adjust sign + if(sign==-1L)this.decimalInput = -this.decimalInput; + + // convert to voltage + this.outputVoltage = (this.decimalInput*this.vRef)/(this.maximumDecimal+1L); + + this.inputSet = true; + } + + // Set input entered as an integer array representing the binary inut in two's complement + // of n+1 bits where n = this.nBits and the extra bit is the sign bit + // Zeroth array element is the least significant bit (LSB) + public void setInput(int[] input){ + int len = input.length; + if(len>this.nBits+1)throw new IllegalArgumentException("length of input array is greater than the DAC bit number plus one"); + for(int i=0; i<len; i++)this.vBinary[i]=input[i]; + if(len<this.nBits+1){ + System.out.println("Class - DtoA; method - setInput(String)"); + System.out.println("The input array is less than DAC number of bits plus one"); + System.out.println("Array assumed to represent a postive unsigned binary number"); + System.out.println("unfilled bits assigned zeros"); + for(int i=len; i<this.nBits+1; i++)this.vBinary[i] = 0; + len = this.nBits+1; + } + + // convert to String + this.binaryInput=""; + for(int i=this.nBits; i>=0; i--){ + this.binaryInput = this.binaryInput + this.vBinary[i]; + } + + // Check if input is negative + long sign = 1L; + int[] vPosBinary = this.vBinary.clone(); + if(this.vBinary[len-1]==1){ + sign = -1L; + vPosBinary = this.negateNegativeBinary(this.vBinary); + } + + // convert positive binary to decimal equivalent + this.decimalInput = DtoA.binaryToDecimal(vPosBinary); + + // adjust sign + if(sign==-1L)this.decimalInput = -this.decimalInput; + + // convert to voltage + this.outputVoltage = (this.decimalInput*this.vRef)/(this.maximumDecimal+1L); + + this.inputSet = true; + } + + + // Set input entered as a decimal equivalent the binary input + public void setInput(long input){ + if(Math.abs(input)>this.maximumDecimal)throw new IllegalArgumentException("abs(input), "+input+", is greater than the maximum decimal representation, "+this.maximumDecimal+", allowed by the set number of bits, "+this.nBits); + this.decimalInput = input; + + // convert to voltage + this.outputVoltage = (input*this.vRef)/(this.maximumDecimal+1L); + + // convert decimal to binary + long dec = this.decimalInput; + int sign = 1; + if(dec<0){ + sign = -1; + dec = -dec; + } + + for(int i=0; i<this.nBits+1; i++)this.vBinary[i] = 0; + boolean test = true; + int ii = 0; + while(test){ + this.vBinary[ii] = (int) (dec % 2); + dec = dec/2L; + ii++; + if(dec==0L)test = false; + } + + // if decimal was negative negate binary + if(sign==-1L)this.vBinary = AtoD.negateBinary(this.vBinary); + + // convert to String + this.binaryInput=""; + for(int i=this.nBits; i>=0; i--){ + this.binaryInput = this.binaryInput + this.vBinary[i]; + } + + this.inputSet = true; + } + + // Enter input as a voltage + public void setInput(double input){ + + if(this.trueDtoA){ + if(Math.abs(input)>this.vRef){ + throw new IllegalArgumentException("The input voltage in this simulation of a DAC must be less than nor equal to the reference voltage\nIf you choose the constructor without an argument list, i.e. an instance of DtoA that is simply a DAC marker\nyou may imput any voltage and the output will be made equal to that voltage"); + } + else{ + this.voltageInput=input; + AtoD adc = new AtoD(this.nBits, this.vRef); + adc.setInput(input); + this.decimalInput = adc.decimalOutput(); + this.binaryInput = adc.binaryOutput(); + this.vBinary = adc.binaryArray(); + } + } + else{ + this.outputVoltage = input; + } + super.sNumer.resetCoeff(0, new Complex(this.outputVoltage/this.voltageInput, 0.0D)); + + this.inputSet = true; + } + + // Convert positive binary to decimal equivalent + private static long binaryToDecimal(int[] binary){ + long decimal = 0L; + for(int i=0; i<binary.length; i++){ + decimal += (long)(Math.pow(2,i)*binary[i]); + } + return decimal; + } + + // Negate a ngative binary number + // Two's complement + private static int[] negateNegativeBinary(int[] binary){ + int nBin = binary.length; + int[] negate = new int[nBin]; + int[] minusOne = new int[nBin]; + for(int i=0; i<nBin; i++){ + minusOne[i]=1; + negate[i]=0; + } + // subtract one + negate = DtoA.addBinary(negate, minusOne); + // invert all bits + for(int i=0; i<nBin; i++){ + if(binary[i] == 0)negate[i] = 1; + } + + return negate; + } + + // Add two binary numbers + private static int[] addBinary(int[] aa, int[] bb){ + int n = aa.length; + int m = bb.length; + int lenMax = n; + int lenMin = m; + if(m>n){ + lenMax = m; + lenMin = n; + } + int[] addition = new int[lenMax]; + int carry = 0; + int sum = 0; + for(int i=0; i<lenMin; i++){ + sum = aa[i] + bb[i] + carry; + switch(sum){ + case 0: addition[i] = 0; + carry = 0; + break; + case 1: addition[i] = 1; + carry = 0; + break; + case 2: addition[i] = 0; + carry = 1; + break; + case 3: addition[i] = 1; + carry = 1; + break; + } + } + + return addition; + } + + // Return output + public double getOutput(){ + if(!this.inputSet)throw new IllegalArgumentException("No input has been entered"); + return this.outputVoltage; + } + + // Return decimal input + public long getDecimalInput(){ + if(!this.inputSet)throw new IllegalArgumentException("No input has been entered"); + if(!this.trueDtoA){ + System.out.println("Class - DtoA; method - getDecimalInput"); + System.out.println("This instance of DtoA is not a true simulation of an DAC"); + System.out.println("It is simple an 'D to A marker'"); + System.out.println("getDecimalInput has returned 0L"); + this.decimalInput = 0L; + } + + return this.decimalInput; + } + + // Return binary input as a String + public String getBinaryInput(){ + if(!this.inputSet)throw new IllegalArgumentException("No input has been entered"); + if(!this.trueDtoA){ + System.out.println("Class - DtoA; method - getBinaryInput"); + System.out.println("This instance of DtoA is not a true simulation of an DAC"); + System.out.println("It is simple an 'D to A marker'"); + System.out.println("getBinaryInput has returned null"); + this.binaryInput = null; + } + + return this.binaryInput; + } + + // Return binary input as int array (zeroth element = LSD) + public int[] getBinaryArray(){ + if(!this.inputSet)throw new IllegalArgumentException("No input has been entered"); + if(!this.trueDtoA){ + System.out.println("Class - DtoA; method - getBinaryInput"); + System.out.println("This instance of DtoA is not a true simulation of an DAC"); + System.out.println("It is simple an 'D to A marker'"); + System.out.println("getBinaryArray has returned null"); + this.vBinary = null; + } + + return this.vBinary; + } + + // Deep copy + public DtoA copy(){ + if(this==null){ + return null; + } + else{ + DtoA bb = new DtoA(); + this.copyBBvariables(bb); + + bb.nBits = this.nBits; + bb.maximumDecimal = this.maximumDecimal; + bb.vRef = this.vRef; + bb.vBinary = this.vBinary.clone(); + bb.trueDtoA = this.trueDtoA; + bb.outputVoltage = this.outputVoltage; + bb.voltageInput = this.voltageInput; + bb.binaryInput = this.binaryInput; + bb.decimalInput = this.decimalInput; + bb.inputSet = this.inputSet; + + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/control/FirstOrder.java b/src/main/java/flanagan/control/FirstOrder.java new file mode 100755 index 0000000000000000000000000000000000000000..f0d85ed092791aeffe4b480a1d8b51f1b8daa980 --- /dev/null +++ b/src/main/java/flanagan/control/FirstOrder.java @@ -0,0 +1,335 @@ +/* Class FirstOrder +* +* This class contains the constructor to create an instance of +* a first order process, +* a.d(output)/dt + b.output = c.input +* and the methods needed to use this process in simulation +* of control loops. +* +* This class is a subclass of the superclass BlackBox. +* +* Author: Michael Thomas Flanagan. +* +* Created: August 2002 +* Updated: 20 April 2003, 3 May 2005, 3 April 2006, 2 July 2006, 6 April 2008, 2 December 2008, 2-7 November 2009 +* +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/FirstOrder.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + + +package flanagan.control; + +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; +import flanagan.plot.*; + +public class FirstOrder extends BlackBox{ + + private double aConst = 1.0D; // a constant in differential equation above + private double bConst = 1.0D; // b constant in differential equation above + private double cConst = 1.0D; // c constant in differential equation above + + // Constructor + // Sets all constants to unity + public FirstOrder(){ + super("FirstOrder"); + super.sPoles = Complex.oneDarray(1); + super.setSnumer(new ComplexPoly(1.0D)); + super.setSdenom(new ComplexPoly(1.0D, 1.0D)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + } + + // Constructor + // within constants set from argument list + public FirstOrder(double aa, double bb, double cc){ + super("FirstOrder"); + this.aConst = aa; + this.bConst = bb; + this.cConst = cc; + super.sPoles = Complex.oneDarray(1); + super.setSnumer(new ComplexPoly(this.cConst)); + super.setSdenom(new ComplexPoly(this.bConst, this.aConst)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + } + + // Set coefficients + public void setCoeff(double aa, double bb, double cc){ + this.aConst = aa; + this.bConst = bb; + this.cConst = cc; + Complex[] num = Complex.oneDarray(1); + num[0].reset(this.cConst, 0.0); + super.sNumer.resetPoly(num); + Complex[] den = Complex.oneDarray(2); + den[0].reset(this.bConst, 0.0); + den[1].reset(this.aConst, 0.0); + super.sDenom.resetPoly(den); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setA(double aa){ + this.aConst = aa; + Complex co = new Complex(this.aConst, 0.0); + super.sDenom.resetCoeff(1, co); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setB(double bb){ + this.bConst = bb; + Complex co = new Complex(this.bConst, 0.0); + super.sDenom.resetCoeff(0, co); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setC(double cc){ + this.cConst = cc; + Complex co = new Complex(this.cConst, 0.0); + super.sNumer.resetCoeff(0, co); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + // Get coefficients + public double getA(){ + return this.aConst; + } + + public double getB(){ + return this.bConst; + } + + public double getC(){ + return this.cConst; + } + + // Get time constant + public double getTimeConstant(){ + return this.aConst/this.bConst; + } + + // Calculate the zeros and poles in the s-domain + protected void calcPolesZerosS(){ + super.sPoles = Complex.oneDarray(1); + super.sPoles[0].setReal(-bConst/aConst); + if(super.sNumerSet)super.sNumerScaleFactor = super.sNumer.coeffCopy(0); + if(super.sDenomSet)super.sDenomScaleFactor = BlackBox.scaleFactor(super.sDenom, super.sPoles); + + } + + // Plots the time course for a step input + public void stepInput(double stepMag, double finalTime){ + + if(this.bConst/this.aConst==0.0){ + // Calculate time course outputs + int n = 51; // number of points on plot + double incrT = finalTime/(double)(n-2); // plotting increment + double cdata[][] = new double [2][n]; // plotting array + + cdata[0][0]=0.0D; + cdata[0][1]=0.0D; + for(int i=2; i<n; i++){ + cdata[0][i]=cdata[0][i-1]+incrT; + } + double kpterm = this.cConst*stepMag/this.bConst; + cdata[1][0]=0.0D; + for(int i=1; i<n; i++){ + cdata[1][i] = kpterm; + } + if(super.deadTime!=0.0D)for(int i=0; i<n; i++)cdata[0][i] += super.deadTime; + + // Plot + PlotGraph pg = new PlotGraph(cdata); + + pg.setGraphTitle("Step Input Transient: Step magnitude = "+stepMag); + pg.setGraphTitle2(this.getName()); + pg.setXaxisLegend("Time"); + pg.setXaxisUnitsName("s"); + pg.setYaxisLegend("Output"); + pg.setPoint(0); + pg.setLine(3); + pg.plot(); + } + else{ + super.stepInput(stepMag, finalTime); + } + } + + + // Perform z transform using an already set delta T + public void zTransform(){ + if(super.deltaT==0.0D)System.out.println("z-transform attempted in FirstOrder with a zero sampling period"); + super.deadTimeWarning("zTransform"); + if(ztransMethod==0){ + this.mapstozAdHoc(); + } + else{ + Complex[] ncoef = null; + Complex[] dcoef = null; + switch(this.integMethod){ + // Trapezium rule + case 0: ncoef = Complex.oneDarray(2); + ncoef[0].reset(this.deltaT*this.cConst,0.0D); + ncoef[1].reset(this.deltaT*this.cConst,0.0D); + super.zNumer=new ComplexPoly(1); + super.zNumer.resetPoly(ncoef); + super.zNumerDeg=1; + dcoef = Complex.oneDarray(2); + dcoef[0].reset(this.bConst*this.deltaT - 2*this.aConst,0.0D); + dcoef[1].reset(this.bConst*this.deltaT + 2*this.aConst,0.0D); + super.zDenom=new ComplexPoly(1); + super.zDenom.resetPoly(dcoef); + super.zDenomDeg=1; + super.zZeros = Complex.oneDarray(1); + super.zZeros[0].reset(-1.0D, 0.0D); + super.zPoles = Complex.oneDarray(1); + super.zPoles[0].reset((2.0D*this.aConst-super.deltaT*this.bConst)/(2.0D*this.aConst+super.deltaT*this.bConst), 0.0D); + break; + // Backward rectangulr rule + case 1: ncoef = Complex.oneDarray(2); + ncoef[0].reset(0.0D,0.0D); + ncoef[1].reset(this.cConst*this.deltaT,0.0D); + super.zNumer=new ComplexPoly(1); + super.zNumer.resetPoly(ncoef); + super.zNumerDeg=1; + dcoef = Complex.oneDarray(2); + dcoef[0].reset(this.bConst*this.deltaT + this.aConst,0.0D); + dcoef[1].reset(this.aConst,0.0D); + super.zDenom=new ComplexPoly(1); + super.zDenom.resetPoly(dcoef); + super.zDenomDeg=1; + super.zZeros = Complex.oneDarray(1); + super.zZeros[0].reset(0.0D, 0.0D); + super.zPoles = Complex.oneDarray(1); + super.zPoles[0].reset(this.aConst/(super.deltaT*this.bConst+this.aConst), 0.0D); + break; + // Foreward rectangular rule + case 2: ncoef = Complex.oneDarray(1); + ncoef[0].reset(this.cConst*this.deltaT,0.0D); + super.zNumer=new ComplexPoly(0); + super.zNumer.resetPoly(ncoef); + super.zNumerDeg=0; + dcoef = Complex.oneDarray(2); + dcoef[0].reset(-this.aConst,0.0D); + dcoef[1].reset(this.bConst*this.deltaT - this.aConst,0.0D); + super.zDenom=new ComplexPoly(1); + super.zDenom.resetPoly(dcoef); + super.zDenomDeg=1; + super.zPoles = Complex.oneDarray(1); + super.zPoles[0].reset(this.aConst/(super.deltaT*this.bConst-this.aConst), 0.0D); + break; + default: System.out.println("Integration method option in FirstOrder must be 0,1 or 2"); + System.out.println("It was set at "+integMethod); + System.out.println("z-transform not performed"); + } + } + } + + // Perform z transform setting delta T + public void zTransform(double deltaT){ + super.deltaT=deltaT; + zTransform(); + } + + // Get the s-domain output for a given s-value and a given input. + public Complex getOutputS(Complex sValue, Complex iinput){ + super.sValue=sValue; + super.inputS=iinput; + return this.getOutputS(); + } + + // Get the s-domain output for the stored input and s-value. + public Complex getOutputS(){ + Complex num = Complex.plusOne(); + num = num.times(this.cConst); + Complex den = new Complex(); + den = this.sValue.times(this.aConst); + den = den.plus(this.bConst); + Complex term = new Complex(); + term = num.over(den); + super.outputS = term.times(super.inputS); + if(super.deadTime!=0.0D)super.outputS = super.outputS.times(Complex.exp(super.sValue.times(-super.deadTime))); + return super.outputS; + } + + // Calculate the current time domain output for a given input and given time + // resets deltaT + public void calcOutputT(double ttime, double inp){ + if(ttime<=time[this.sampLen-1])throw new IllegalArgumentException("Current time equals or is less than previous time"); + super.deltaT = ttime - super.time[this.sampLen-1]; + super.sampFreq = 1.0D/super.deltaT; + super.deadTimeWarning("calcOutputT(time, input)"); + for(int i=0; i<super.sampLen-2; i++){ + super.time[i]=super.time[i+1]; + super.inputT[i]=super.inputT[i+1]; + super.outputT[i]=super.outputT[i+1]; + } + super.time[super.sampLen-1]=ttime; + super.inputT[super.sampLen-1]=inp; + super.outputT[super.sampLen-1]=Double.NaN; + this.calcOutputT(); + } + + // Get the output for the stored sampled input, time and deltaT. + public void calcOutputT(){ + super.deadTimeWarning("calcOutputT()"); + super.outputT[sampLen-1] = (this.bConst*super.inputT[sampLen-1] + this.aConst*(super.inputT[sampLen-1]-super.inputT[sampLen-2])/super.deltaT)/this.cConst; + } + + + // Get the s-domain zeros + public Complex[] getSzeros(){ + System.out.println("This standard first order process (class FirstOrder) has no s-domain zeros"); + return null; + } + + + // Deep copy + public FirstOrder copy(){ + if(this==null){ + return null; + } + else{ + FirstOrder bb = new FirstOrder(); + this.copyBBvariables(bb); + + bb.aConst = this.aConst; + bb.bConst = this.bConst; + bb.cConst = this.cConst; + + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/control/HighPassPassive.java b/src/main/java/flanagan/control/HighPassPassive.java new file mode 100755 index 0000000000000000000000000000000000000000..60c1b4110c1a0b4af1990a0f6db929fb69271891 --- /dev/null +++ b/src/main/java/flanagan/control/HighPassPassive.java @@ -0,0 +1,157 @@ +/* Class HighPassPassive +* +* This class contains the constructor to create an instance of +* a low pass filter: +* V(out) = V(in)RCjomega/(1 +RCjomega) +* and the methods needed to use this process in simulation +* of control loops. +* +* This class is a subclass of the superclass BlackBox. +* +* Author: Michael Thomas Flanagan. +* +* Created: 21 May 2005 +* Updated: 2 July 2006, 6 April 2008, 2 December 2008, 2-7 November 2009 +* +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/HighPassPassive.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2005 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, +* this list of conditions and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission +* from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.control; +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; + +public class HighPassPassive extends BlackBox{ + + private double resistance = 0.0D; // Resistance value, R ohms + private double capacitance = 0.0D; // Capacitance value, C farads + private double timeConstant = 0.0D; // Time constant, RC seconds + private boolean setR = false; // = true when resistance set + private boolean setC = false; // = true when capacitance set + + // Constructor + // Sets time constant and order to unity + public HighPassPassive(){ + super("PassiveHighPass"); + super.sZeros = Complex.oneDarray(1); + super.sPoles = Complex.oneDarray(1); + super.setSnumer(new ComplexPoly(0.0D, 1.0D)); + super.setSdenom(new ComplexPoly(1.0D, 1.0D)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + this.timeConstant = 1.0D; + } + + + public void setResistance(double res){ + this.resistance = res; + this.timeConstant = res*this.capacitance; + this.calcPolesZerosS(); + super.sNumer = ComplexPoly.rootsToPoly(this.sZeros); + for(int i=0; i<=super.sNumerDeg;i++)super.sNumer.resetCoeff(i, super.sNumer.coeffCopy(i).times(Math.pow(this.timeConstant, i))); + super.sDenom = ComplexPoly.rootsToPoly(this.sPoles); + super.addDeadTimeExtras(); + this.setR = true; + } + + public void setCapacitance(double cap){ + this.capacitance = cap; + this.timeConstant = cap*this.resistance; + this.calcPolesZerosS(); + super.sNumer = ComplexPoly.rootsToPoly(this.sZeros); + for(int i=0; i<=super.sNumerDeg;i++)super.sNumer.resetCoeff(i, super.sNumer.coeffCopy(i).times(Math.pow(this.timeConstant, i))); + super.sDenom = ComplexPoly.rootsToPoly(this.sPoles); + super.addDeadTimeExtras(); + this.setC = true; + } + + public void setTimeConstant(double tau){ + this.timeConstant = tau; + this.calcPolesZerosS(); + super.sNumer = ComplexPoly.rootsToPoly(this.sZeros); + for(int i=0; i<=super.sNumerDeg;i++)super.sNumer.resetCoeff(i, super.sNumer.coeffCopy(i).times(Math.pow(this.timeConstant, i))); + super.sDenom = ComplexPoly.rootsToPoly(this.sPoles); + super.addDeadTimeExtras(); + } + + public double getResistance(){ + if(this.setR){ + return this.resistance; + } + else{ + System.out.println("Class; HighPassPassive, method: getResistance"); + System.out.println("No resistance has been entered; zero returned"); + return 0.0D; + } + } + + public double getCapacitance(){ + if(this.setC){ + return this.capacitance; + } + else{ + System.out.println("Class; HighPassPassive, method: getCapacitance"); + System.out.println("No capacitance has been entered; zero returned"); + return 0.0D; + } + } + + public double getTimeConstant(){ + return this.timeConstant; + } + + // Calculate the zeros and poles in the s-domain + protected void calcPolesZerosS(){ + super.sZeros[0].setReal(0.0D); + super.sPoles[0].setReal(-this.timeConstant); + super.sNumerScaleFactor = BlackBox.scaleFactor(super.sNumer, super.sZeros); + super.sDenomScaleFactor = BlackBox.scaleFactor(super.sDenom, super.sPoles); + } + + // Deep copy + public HighPassPassive copy(){ + if(this==null){ + return null; + } + else{ + HighPassPassive bb = new HighPassPassive(); + this.copyBBvariables(bb); + + bb.resistance = this.resistance; + bb.capacitance = this.capacitance; + bb.timeConstant = this.timeConstant; + bb.setR = this.setR; + bb.setC = this.setC; + + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/control/LowPassPassive.java b/src/main/java/flanagan/control/LowPassPassive.java new file mode 100755 index 0000000000000000000000000000000000000000..fa35cf14507a23c93e4725dd41caae2cbad67d5c --- /dev/null +++ b/src/main/java/flanagan/control/LowPassPassive.java @@ -0,0 +1,148 @@ +/* Class LowPassPassive +* +* This class contains the constructor to create an instance of +* a low pass filter: +* V(out) = V(in)/(1 +RCjomega) +* and the methods needed to use this process in simulation +* of control loops. +* +* This class is a subclass of the superclass BlackBox. +* +* Author: Michael Thomas Flanagan. +* +* Created: 21 May 2005 +* Updated: 2 July 2006, 6 April 2008, 2 December 2008, 2-7 November 2009 +* +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/LowPassPassive.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2005 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, +* this list of conditions and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission +* from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.control; +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; + +public class LowPassPassive extends BlackBox{ + + private double resistance = 0.0D; // Resistance value, R ohms + private double capacitance = 0.0D; // Capacitance value, C farads + private double timeConstant = 0.0D; // Time constant, RC seconds + private boolean setR = false; // = true when resistance set + private boolean setC = false; // = true when capacitance set + + // Constructor + + // Sets time constant to unity and the order to unity + public LowPassPassive(){ + super("PassiveLowPass"); + super.sPoles = Complex.oneDarray(1); + super.setSnumer(new ComplexPoly(1.0D)); + super.setSdenom(new ComplexPoly(1.0D, 1.0D)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + this.timeConstant = 1.0D; + } + + public void setResistance(double res){ + this.resistance = res; + this.timeConstant = res*this.capacitance; + this.calcPolesZerosS(); + super.sDenom = ComplexPoly.rootsToPoly(this.sPoles); + super.addDeadTimeExtras(); + this.setR = true; + } + + public void setCapacitance(double cap){ + this.capacitance = cap; + this.timeConstant = cap*this.resistance; + this.calcPolesZerosS(); + super.sDenom = ComplexPoly.rootsToPoly(this.sPoles); + super.addDeadTimeExtras(); + this.setC = true; + } + + public void setTimeConstant(double tau){ + this.timeConstant = tau; + this.calcPolesZerosS(); + super.sDenom = ComplexPoly.rootsToPoly(this.sPoles); + super.addDeadTimeExtras(); + } + + public double getResistance(){ + if(this.setR){ + return this.resistance; + } + else{ + System.out.println("Class; LowPassPassive, method: getResistance"); + System.out.println("No resistance has been entered; zero returned"); + return 0.0D; + } + } + + public double getCapacitance(){ + if(this.setC){ + return this.capacitance; + } + else{ + System.out.println("Class; LowPassPassive, method: getCapacitance"); + System.out.println("No capacitance has been entered; zero returned"); + return 0.0D; + } + } + + public double getTimeConstant(){ + return this.timeConstant; + } + + // Calculate the zeros and poles in the s-domain + protected void calcPolesZerosS(){ + super.sPoles[0].setReal(-this.timeConstant); + super.sNumerScaleFactor = super.sNumer.coeffCopy(0); + super.sDenomScaleFactor = BlackBox.scaleFactor(super.sDenom, super.sPoles); + } + + // Deep copy + public LowPassPassive copy(){ + if(this==null){ + return null; + } + else{ + LowPassPassive bb = new LowPassPassive(); + this.copyBBvariables(bb); + + bb.resistance = this.resistance; + bb.capacitance = this.capacitance; + bb.timeConstant = this.timeConstant; + bb.setR = this.setR; + bb.setC = this.setC; + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/control/OpenLoop.java b/src/main/java/flanagan/control/OpenLoop.java new file mode 100755 index 0000000000000000000000000000000000000000..b9d69c724212d5d5503e0b70d846592b2b9344e7 --- /dev/null +++ b/src/main/java/flanagan/control/OpenLoop.java @@ -0,0 +1,605 @@ +/* Class OpenLoop +* +* This class supports the creation of a path of Black Boxes +* i.e. of instances of BlackBox and of any of its subclasses, +* e.g. PropIntDeriv, FirstOrder, and the methods to combine +* these into both a single instance of BlackBox and a Vector +* of analogue segments, digital segments and converters. +* +* Author: Michael Thomas Flanagan. +* +* Created: August 2002 +* Updated: 12 July 2003, 10 May 2005, 2 July 2006, 7 June 2007, 6 April 2008, 5 July 2008, 2-7 November 2009 +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/OpenLoop.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* +* Copyright (c) 2002 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.control; + +import java.util.ArrayList; +import java.util.Vector; +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; + +public class OpenLoop extends BlackBox{ + private ArrayList<BlackBox> openPath = new ArrayList<BlackBox>(); // open path boxes + private ArrayList<Object> segments = new ArrayList<Object>(); // start of segment, end of segment, type of each segment, i.e. analogue, digital, AtoD, DtoA, ZOH + + private int nBoxes = 0; // number of boxes in original path + private int nSeg = 0; // number of analogue, digital, AtoD, ZOH segments + + private boolean checkPath = false; // true if segment has been called + private boolean checkNoMix = true; // true - no ADC or DAC + private boolean checkConsolidate = false; // true if consolidate has been called + + private boolean[] adcs = null; // true if box = ADC + private boolean[] dacs = null; // true ifbox = DAC + private boolean[] zeroHolds = null; // true ifbox = Zero Order Hold + + // Constructor + public OpenLoop(){ + super("OpenLoop"); + } + + // Add box to the open path + public void addBoxToPath(BlackBox box){ + this.openPath.add(box); + this.nBoxes++; + } + + // Consolidate all boxes into appropriate segments and combine all boxes into one box + public void consolidate(){ + // Empty segments ArrayList if openPath ArrayList has been updated + if(!segments.isEmpty()){ + segments.clear(); + this.nBoxes = 0; + this.nSeg = 0; + this.checkNoMix = true; + this.checkPath = false; + } + + // Find analogue, digital and conversion segments in OpenLoop + this.segment(); + + // Combine all boxes into a single box and make this instance that combined box + BlackBox aa = null; + if(this.nSeg==1){ + if(this.nBoxes==1){ + aa = (BlackBox) this.openPath.get(0); + } + else{ + aa = (BlackBox) this.segments.get(3); + } + } + else{ + aa = this.combineSegment(0, this.nBoxes); + } + super.sNumer = aa.sNumer.copy(); + super.sDenom = aa.sDenom.copy(); + super.sNumerPade = aa.sNumerPade.copy(); + super.sDenomPade = aa.sDenomPade.copy(); + super.sNumerDeg = aa.sNumerDeg; + super.sDenomDeg = aa.sDenomDeg; + super.sNumerDegPade = aa.sNumerDegPade; + super.sDenomDegPade = aa.sDenomDegPade; + super.sNumerSet = true; + super.sDenomSet = true; + super.deadTime = aa.deadTime; + super.sZeros = Complex.copy(aa.sZeros); + super.sPoles = Complex.copy(aa.sPoles); + super.sZerosPade = Complex.copy(aa.sZerosPade); + super.sPolesPade = Complex.copy(aa.sPolesPade); + super.padeAdded=true; + if(super.sNumerDeg==0){ + super.sNumerScaleFactor = super.sNumer.coeffCopy(0); + } + else{ + super.sNumerScaleFactor = BlackBox.scaleFactor(super.sNumer, super.sZeros); + } + if(super.sDenomDeg==0){ + super.sDenomScaleFactor = super.sDenom.coeffCopy(0); + } + else{ + super.sDenomScaleFactor = BlackBox.scaleFactor(super.sDenom, super.sPoles); + } + this.checkConsolidate = true; + } + + // Find analogue and digital segments + public void segment(){ + // Find ADCs, DACs and ZeroOrderHolds + this.adcs = new boolean[nBoxes]; + int nADCs = 0; + this.dacs = new boolean[nBoxes]; + int nDACs = 0; + this.zeroHolds = new boolean[nBoxes]; + int nZeroHolds = 0; + String thisName = null; + for(int i=0; i<nBoxes; i++){ + adcs[i] = false; + dacs[i] = false; + zeroHolds[i] = false; + BlackBox aa = openPath.get(i); + thisName = aa.fixedName; + if(thisName.equals("ADC")){ + adcs[i]=true; + nADCs++; + } + else{ + if(thisName.equals("DAC")){ + dacs[i]=true; + nDACs++; + } + else{ + if(thisName.equals("ZeroOrderHold")){ + zeroHolds[i]=true; + nZeroHolds++; + } + } + } + } + + if(nADCs==0 && nDACs==0){ + this.nSeg = 1; // number of analogue, digital, AtoD, ZOH segments + this.checkNoMix = true; // true - no ADC or DAC + this.checkPath = true; // true if segment has been called + this.segments.add(new Integer(0)); + this.segments.add(new Integer(nBoxes-1)); + this.segments.add("analogue"); + BlackBox bb = this.combineSegment(0, nBoxes-1); + this.segments.add(bb); + } + else{ + this.nSeg = 0; + int adc0 = 0; + int dac0 = 0; + boolean adcFirst = false; + if(nADCs>0 && nDACs>0){ + // first adc or dac + boolean test0 = true; + adc0 = 0; + while(test0){ + if(adcs[adc0]){ + test0 = false; + } + else{ + adc0++; + if(adc0>=nBoxes){ + test0 = false; + } + } + } + test0 = true; + while(test0){ + if(dacs[dac0]){ + test0 = false; + } + else{ + dac0++; + if(dac0>=nBoxes){ + test0 = false; + } + } + } + if(adc0<dac0)adcFirst =true; + } + else{ + if(nADCs>0)adcFirst=true; + } + boolean adswitch = adcFirst; + this.nSeg++; + + int nextStart = 0; + if(adcFirst){ + this.segments.add(new Integer(0)); + this.segments.add(new Integer(adc0)); + this.segments.add("digital"); + BlackBox bb = this.combineSegment(0, adc0); + this.segments.add(bb); + nextStart = adc0+1; + } + else{ + this.segments.add(new Integer(0)); + this.segments.add(new Integer(dac0)); + this.segments.add("analogue"); + BlackBox bb = this.combineSegment(0, dac0); + this.segments.add(bb); + nextStart = dac0+1; + } + + // Find all analogue and digital segments + boolean test1 = true; + if(nextStart>=this.nBoxes)test1 = false; + while(test1){ + if(adswitch){ + nextStart = nextDigitalSegment(nextStart); + adswitch = false; + } + else{ + nextStart = nextAnalogueSegment(nextStart); + adswitch = true; + } + if(nextStart>=this.nBoxes)test1 = false; + } + + } + + + + } + + // Find next digital segment + private int nextDigitalSegment(int box0){ + // next adc + int nextAdc = nBoxes; + boolean endFound = false; + boolean test = true; + int ii = box0; + while(test){ + if(this.adcs[ii]){ + nextAdc = ii; + test = false; + } + else{ + ii++; + if(ii>=nBoxes)test = false; + } + } + + // next dac + int nextDac = nBoxes; + test = true; + ii = box0; + while(test){ + if(dacs[ii]){ + nextDac = ii; + test = false; + } + else{ + ii++; + if(ii>=nBoxes){ + test = false; + endFound = true; + } + } + } + if(endFound)nextDac = nBoxes-1; + if(nextAdc<nextDac)throw new IllegalArgumentException("Two consecutive ADCs with no intervening DAC"); + this.nSeg++; + this.segments.add(new Integer(0)); + this.segments.add(new Integer(nextDac)); + this.segments.add("digital"); + BlackBox bb = this.combineSegment(0, nextDac); + this.segments.add(bb); + + return nextDac + 1; + } + + // Find next analogue segment + private int nextAnalogueSegment(int box0){ + // next adc + int nextAdc = nBoxes; + boolean endFound = false; + boolean test = true; + int ii = box0; + while(test){ + if(this.adcs[ii]){ + nextAdc = ii; + test = false; + } + else{ + ii++; + if(ii>=nBoxes){ + test = false; + endFound = true; + } + } + } + + // next dac + int nextDac = nBoxes; + test = true; + ii = box0; + while(test){ + if(dacs[ii]){ + nextDac = ii; + test = false; + } + else{ + ii++; + if(ii>=nBoxes){ + test = false; + } + } + } + if(endFound)nextAdc = nBoxes-1; + if(nextDac<nextAdc)throw new IllegalArgumentException("Two consecutive DACs with no intervening ADC"); + this.nSeg++; + this.segments.add(new Integer(0)); + this.segments.add(new Integer(nextAdc)); + this.segments.add("digital"); + BlackBox bb = this.combineSegment(0, nextAdc); + this.segments.add(bb); + + return nextAdc+1; + } + + // Combine all boxes between iLow and iHigh into one box + public BlackBox combineSegment(int iLow, int iHigh){ + ArrayList<Complex> zeros = new ArrayList<Complex>(); + ArrayList<Complex> poles = new ArrayList<Complex>(); + ArrayList<Complex> zerosPade = new ArrayList<Complex>(); + ArrayList<Complex> polesPade = new ArrayList<Complex>(); + + + BlackBox aa = new BlackBox(); // Black Box to be returned + + int nBoxSeg = iHigh - iLow + 1; // number of boxes in segment + + BlackBox bb = openPath.get(iLow); // first box in segment + if(!bb.padeAdded)bb.transferPolesZeros(); + + aa.sNumerPade = bb.sNumerPade.copy(); + aa.sDenomPade = bb.sDenomPade.copy(); + aa.sNumer = bb.sNumer.copy(); + aa.sDenom = bb.sDenom.copy(); + + aa.sNumerDegPade = bb.sNumerDegPade; + aa.sDenomDegPade = bb.sDenomDegPade; + aa.sNumerDeg = bb.sNumerDeg; + aa.sDenomDeg = bb.sDenomDeg; + + if(aa.sNumerDegPade>0){ + Complex[] bbsZerosPade = Complex.copy(bb.sZerosPade); + for(int i=0; i<aa.sNumerDegPade; i++)zerosPade.add(bbsZerosPade[i]); + } + if(aa.sDenomDegPade>0){ + Complex[] bbsPolesPade = Complex.copy(bb.sPolesPade); + for(int i=0; i<aa.sDenomDegPade; i++)polesPade.add(bbsPolesPade[i]); + } + if(aa.sNumerDeg>0){ + Complex[] bbsZeros = Complex.copy(bb.sZeros); + for(int i=0; i<aa.sNumerDeg; i++)zeros.add(bbsZeros[i]); + } + if(aa.sDenomDeg>0){ + Complex[] bbsPoles = Complex.copy(bb.sPoles); + for(int i=0; i<aa.sDenomDeg; i++)poles.add(bbsPoles[i]); + } + + aa.deadTime = bb.deadTime; + aa.sNumerScaleFactor = bb.sNumerScaleFactor.copy(); + aa.sDenomScaleFactor = bb.sDenomScaleFactor.copy(); + + for(int i=1; i<nBoxSeg; i++){ + bb = this.openPath.get(i+iLow); + if(!bb.padeAdded)bb.transferPolesZeros(); + if(aa.sNumerPade==null){ + if(bb.sNumerPade!=null){ + aa.sNumerPade = bb.sNumerPade.copy(); + } + } + else{ + if(bb.sNumerPade!=null){ + aa.sNumerPade = aa.sNumerPade.times(bb.sNumerPade); + } + } + + if(aa.sNumer==null){ + if(bb.sNumer!=null){ + aa.sNumer = bb.sNumer.copy(); + } + } + else{ + if(bb.sNumer!=null){ + aa.sNumer = aa.sNumer.times(bb.sNumer); + } + } + + if(aa.sDenom==null){ + if(bb.sDenom!=null){ + aa.sDenom = bb.sDenom.copy(); + } + } + else{ + if(bb.sDenom!=null){ + aa.sDenom = aa.sDenom.times(bb.sDenom); + } + } + + if(aa.sDenomPade==null){ + if(bb.sDenomPade!=null){ + aa.sDenomPade = bb.sDenomPade.copy(); + } + } + else{ + if(bb.sDenomPade!=null){ + aa.sDenomPade = aa.sDenomPade.times(bb.sDenomPade); + } + } + + aa.sNumerDegPade += bb.sNumerDegPade; + aa.sDenomDegPade += bb.sDenomDegPade; + aa.sNumerDeg += bb.sNumerDeg; + aa.sDenomDeg += bb.sDenomDeg; + + aa.sNumerScaleFactor = bb.sNumerScaleFactor.times(aa.sNumerScaleFactor); + aa.sDenomScaleFactor = bb.sDenomScaleFactor.times(aa.sDenomScaleFactor); + + aa.deadTime += bb.deadTime; + + if(bb.sNumerDegPade>0){ + Complex[] bbsZerosPade = Complex.copy(bb.sZerosPade); + for(int ii=0; ii<bb.sNumerDegPade; ii++)zerosPade.add(bbsZerosPade[ii]); + } + if(bb.sDenomDegPade>0){ + Complex[] bbsPolesPade = Complex.copy(bb.sPolesPade); + for(int ii=0; ii<bb.sDenomDegPade; ii++)polesPade.add(bbsPolesPade[ii]); + } + if(bb.sNumerDeg>0){ + Complex[] bbsZeros = Complex.copy(bb.sZeros); + for(int ii=0; ii<bb.sNumerDeg; ii++)zeros.add(bbsZeros[ii]); + } + if(bb.sDenomDeg>0){ + Complex[] bbsPoles = Complex.copy(bb.sPoles); + for(int ii=0; ii<bb.sDenomDeg; ii++)poles.add(bbsPoles[ii]); + } + } + + if(aa.sNumerDegPade>0){ + aa.sZerosPade = Complex.oneDarray(aa.sNumerDegPade); + for(int ii=0; ii<aa.sNumerDegPade; ii++)aa.sZerosPade[ii] = zerosPade.get(ii); + } + if(aa.sDenomDegPade>0){ + aa.sPolesPade = Complex.oneDarray(aa.sDenomDegPade); + for(int ii=0; ii<aa.sDenomDegPade; ii++)aa.sPolesPade[ii] = polesPade.get(ii); + } + if(aa.sNumerDeg>0){ + aa.sZeros = Complex.oneDarray(aa.sNumerDeg); + for(int ii=0; ii<aa.sNumerDeg; ii++)aa.sZeros[ii] = zeros.get(ii); + } + if(aa.sDenomDeg>0){ + aa.sPoles = Complex.oneDarray(aa.sDenomDeg); + for(int ii=0; ii<aa.sDenomDeg; ii++)aa.sPoles[ii] = poles.get(ii); + } + return aa; + + } + + // Return number of boxes in path + public int getNumberOfBoxes(){ + if(!checkConsolidate)this.consolidate(); + return this.nBoxes; + } + + // Return segment ArrayList + public ArrayList<Object> getSegmentsArrayList(){ + if(!checkConsolidate)this.consolidate(); + return this.segments; + } + + // Return segment Vector + public Vector<Object> getSegmentsVector(){ + if(!checkConsolidate)this.consolidate(); + ArrayList<Object> seg = this.segments; + Vector<Object> ret = null; + if(seg!=null){ + int n = seg.size(); + ret = new Vector<Object>(n); + for(int i=0; i<n; i++)ret.addElement(seg.get(i)); + } + return ret; + } + + // Return number of segments in path + public int getNumberOfSegments(){ + if(!checkConsolidate)this.consolidate(); + return this.nSeg; + } + + // Return name of all boxes in path + public String getNamesOfBoxes(){ + if(!checkConsolidate)this.consolidate(); + String names = ""; + for(int i=0; i<this.nBoxes; i++){ + BlackBox bb = openPath.get(i); + names = names + i +": "+bb.getName() + " "; + } + return names; + } + + // Remove all boxes from the path + public void removeAllBoxes(){ + // Empty openPath ArrayList + if(!openPath.isEmpty()){ + openPath.clear(); + } + + // Empty segments ArrayList + if(!segments.isEmpty()){ + segments.clear(); + } + this.nSeg = 0; + this.checkNoMix = true; + this.checkPath = false; + this.nBoxes = 0; + this.checkConsolidate = false; + this.adcs = null; + this.dacs = null; + this.zeroHolds = null; + + } + + // return checkNoMix + public boolean getCheckNoMix(){ + return this.checkNoMix; + } + + + // Deep copy + public OpenLoop copy(){ + if(this==null){ + return null; + } + else{ + OpenLoop bb = new OpenLoop(); + this.copyBBvariables(bb); + + bb.nBoxes = this.nBoxes; + bb.nSeg = this.nSeg; + bb.checkPath = this.checkPath; + bb.checkNoMix = this.checkNoMix; + bb.checkConsolidate = this.checkConsolidate; + if(this.openPath.size()==0){ + bb.openPath = new ArrayList<BlackBox>(); + } + else{ + for(int i=0; i<openPath.size(); i++)bb.openPath.add((this.openPath.get(i)).copy()); + } + if(this.segments.size()==0){ + bb.segments = new ArrayList<Object>(); + } + else{ + int j=0; + for(int i=0; i<this.nSeg; i++){ + Integer holdI1 = (Integer)this.segments.get(j); + int ii = holdI1.intValue(); + bb.segments.add(new Integer(ii)); + j++; + Integer holdI2 = (Integer)this.segments.get(j); + ii = holdI2.intValue(); + bb.segments.add(new Integer(ii)); + j++; + String holdS = (String)this.segments.get(j); + bb.segments.add(holdS); + j++; + bb.segments.add(((BlackBox)this.segments.get(j)).copy()); + j++; + } + } + + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} diff --git a/src/main/java/flanagan/control/Prop.java b/src/main/java/flanagan/control/Prop.java new file mode 100755 index 0000000000000000000000000000000000000000..ef0f8e0793666b1ce7acafd612ea19a39cc53e61 --- /dev/null +++ b/src/main/java/flanagan/control/Prop.java @@ -0,0 +1,259 @@ +/* Class Prop +* +* This class contains the constructor to create an instance of +* a Proportional gain controller and the methods +* needed to use this controller in control loops in the time +* domain, Laplace transform s domain or the z-transform z domain. +* +* This class is a subclass of the superclass BlackBox. +* +* Author: Michael Thomas Flanagan. +* +* Created: August 2002 +* Updated: 20 April 2003, 3 May 2005, July 2006, 6 April 2008, 30 October 2009, 7 November 2009 +* +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Prop.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + + +package flanagan.control; +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; +import flanagan.plot.Plot; +import flanagan.plot.PlotGraph; + +public class Prop extends BlackBox{ + private double kp = 1.0D; // proportional gain + + // Constructor - unit proportional gain + public Prop(){ + super("Prop"); + super.setSnumer(new ComplexPoly(1.0D)); + super.setSdenom(new ComplexPoly(1.0D)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + super.sNumerScaleFactor = Complex.plusOne(); + super.sDenomScaleFactor = Complex.plusOne(); + } + + // Constructor - set P gain + public Prop(double kp){ + super("Prop"); + this.kp=kp; + super.setSnumer(new ComplexPoly(this.kp)); + super.setSdenom(new ComplexPoly(1.0D)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + super.sNumerScaleFactor = new Complex(kp, 0.0); + super.sDenomScaleFactor = Complex.plusOne(); + } + + // Set the proportional gain + public void setKp(double kp){ + this.kp=kp; + Complex num = new Complex(this.kp, 0.0D); + super.sNumer.resetCoeff(0, num); + super.addDeadTimeExtras(); + super.sNumerScaleFactor = new Complex(kp, 0.0); + } + + // Get the proprtional gain + public double getKp(){ + return this.kp; + } + + // Perform z transform using an already set delta T + public void zTransform(){ + super.zNumerDeg = 0; + super.zDenomDeg = 0; + super.zNumer = new ComplexPoly(this.kp); + super.zDenom = new ComplexPoly(1.0D); + } + + // Perform z transform setting delta T + public void zTransform(double deltaT){ + super.deltaT=deltaT; + zTransform(); + } + + // Plots the time course for a step input + public void stepInput(double stepMag, double finalTime){ + + // Calculate time course outputs + int n = 51; // number of points on plot + double incrT = finalTime/(double)(n-2); // plotting increment + double cdata[][] = new double [2][n]; // plotting array + + cdata[0][0]=0.0D; + cdata[0][1]=0.0D; + for(int i=2; i<n; i++){ + cdata[0][i]=cdata[0][i-1]+incrT; + } + double kpterm = this.kp*stepMag; + cdata[1][0]=0.0D; + for(int i=1; i<n; i++){ + cdata[1][i] = kpterm; + } + if(super.deadTime!=0.0D)for(int i=0; i<n; i++)cdata[0][i] += super.deadTime; + + // Plot + PlotGraph pg = new PlotGraph(cdata); + + pg.setGraphTitle("Step Input Transient: Step magnitude = "+stepMag); + pg.setGraphTitle2(this.getName()); + pg.setXaxisLegend("Time"); + pg.setXaxisUnitsName("s"); + pg.setYaxisLegend("Output"); + pg.setPoint(0); + pg.setLine(3); + pg.plot(); + } + + // Plots the time course for a unit step input + public void stepInput(double finalTime){ + this.stepInput(1.0D, finalTime); + } + + // Plots the time course for an nth order ramp input (at^n) + public void rampInput(double rampGradient, int rampOrder, double finalTime){ + + if(rampOrder==0){ + // Check if really a step input (rampOrder, n = 0) + this.stepInput(rampGradient, finalTime); + } + else{ + // Calculate time course outputs + int n = 50; // number of points on plot + double incrT = finalTime/(double)(n-1); // plotting increment + double cdata[][] = new double [2][n]; // plotting array + double sum = 0.0D; // integration sum + + cdata[0][0]=0.0D; + cdata[1][0]=0.0D; + for(int i=1; i<n; i++){ + cdata[0][i]=cdata[0][i-1]+incrT; + cdata[1][i] = rampGradient*Math.pow(cdata[0][i],rampOrder)*this.kp; + } + if(super.deadTime!=0.0D)for(int i=0; i<n; i++)cdata[0][i] += super.deadTime; + + // Plot + PlotGraph pg = new PlotGraph(cdata); + + pg.setGraphTitle("Ramp (a.t^n) Input Transient: ramp gradient (a) = "+rampGradient + " ramp order (n) = " + rampOrder); + pg.setGraphTitle2(this.getName()); + pg.setXaxisLegend("Time"); + pg.setXaxisUnitsName("s"); + pg.setYaxisLegend("Output"); + pg.setPoint(0); + pg.plot(); + } + } + + // Plots the time course for an nth order ramp input (t^n) + public void rampInput(int rampOrder, double finalTime){ + double rampGradient = 1.0D; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Plots the time course for a first order ramp input (at) + public void rampInput(double rampGradient, double finalTime){ + int rampOrder = 1; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Plots the time course for a unit ramp input (t) + public void rampInput(double finalTime){ + double rampGradient = 1.0D; + int rampOrder = 1; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Get the s-domain output for a given s-value and a given input. + public Complex getOutputS(Complex sValue, Complex iinput){ + super.sValue=sValue; + super.inputS=iinput; + super.outputS=super.inputS.times(this.kp); + if(super.deadTime!=0.0D)super.outputS = super.outputS.times(Complex.exp(super.sValue.times(-super.deadTime))); + return super.outputS; + } + + // Get the s-domain output for the stored input and s-value. + public Complex getOutputS(){ + super.outputS=super.inputS.times(this.kp); + if(super.deadTime!=0.0D)super.outputS = super.outputS.times(Complex.exp(super.sValue.times(-super.deadTime))); + return super.outputS; + } + + + // Calculate the current time domain output for a given input and given time + // resets deltaT + public void calcOutputT(double ttime, double inp){ + if(ttime<=time[this.sampLen-1])throw new IllegalArgumentException("Current time equals or is less than previous time"); + super.deltaT = ttime - super.time[this.sampLen-1]; + super.sampFreq = 1.0D/super.deltaT; + super.deadTimeWarning("calcOutputT(time, input)"); + for(int i=0; i<super.sampLen-2; i++){ + super.time[i]=super.time[i+1]; + super.inputT[i]=super.inputT[i+1]; + super.outputT[i]=super.outputT[i+1]; + } + super.time[super.sampLen-1]=ttime; + super.inputT[super.sampLen-1]=inp; + super.outputT[super.sampLen-1]=Double.NaN; + this.calcOutputT(); + } + + // Get the output for the stored sampled input and time. + public void calcOutputT(){ + // proportional term + super.outputT[super.sampLen-1] = this.kp*super.inputT[super.sampLen-1]; + } + + // Get the s-domain zeros + public Complex[] getZerosS(){ + System.out.println("Proportional gain controller has no s-domain zeros"); + return null; + } + + // Get the s-domain poles + public Complex[] getPolesS(){ + System.out.println("Proportional gain controller has no s-domain poles"); + return null; + } + + // Deep copy + public Prop copy(){ + if(this==null){ + return null; + } + else{ + Prop bb = new Prop(); + this.copyBBvariables(bb); + + bb.kp = this.kp; + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/control/PropDeriv.java b/src/main/java/flanagan/control/PropDeriv.java new file mode 100755 index 0000000000000000000000000000000000000000..9fabfc150068cdf40b99fe18b70f443f0a8aa8f5 --- /dev/null +++ b/src/main/java/flanagan/control/PropDeriv.java @@ -0,0 +1,295 @@ +/* Class PropDeriv +* +* This class contains the constructor to create an instance of +* a Proportional plus Derivative(PD) controller and the methods +* needed to use this controller in control loops in the time +* domain, Laplace transform s domain or the z-transform z domain. +* +* This class is a subclass of the superclass BlackBox. +* +* Author: Michael Thomas Flanagan. +* +* Created: August 2002 +* Updated: 17 April 2003, 2 May 2005, 2 July 2006, 6 April 2008, 30 October 2009, 7 November 2009 +* +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/PropDeriv.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2006 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + + +package flanagan.control; + +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; +import flanagan.plot.Plot; +import flanagan.plot.PlotGraph; + +public class PropDeriv extends BlackBox{ + private double kp = 1.0D; // proportional gain + private double td = 0.0D; // derivative time constant + private double kd = 0.0D; // derivative gain + + // Constructor - unit proportional gain, zero derivative gain + public PropDeriv(){ + super("PropDeriv"); + super.sNumerDeg = 1; + super.sDenomDeg = 0; + super.setSnumer(new ComplexPoly(1.0D, 0.0D)); + super.setSdenom(new ComplexPoly(1.0D)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + + } + + // Set the proportional gain + public void setKp(double kp){ + this.kp = kp; + super.sNumer.resetCoeff(0, new Complex(this.kp, 0.0D)); + if(super.sZeros==null)super.sZeros = Complex.oneDarray(1); + super.sZeros[0].reset(-this.kp/this.kd, 0.0D); + super.addDeadTimeExtras(); + } + + // Set the derivative gain + public void setKd(double kd){ + this.kd=kd; + this.td=kd/this.kp; + super.sNumer.resetCoeff(1, new Complex(this.kd, 0.0D)); + if(super.sZeros==null)super.sZeros = Complex.oneDarray(1); + super.sZeros[0].reset(-this.kp/this.kd, 0.0D); + super.addDeadTimeExtras(); + } + + // Set the derivative time constant + public void setTd(double td){ + this.td=td; + this.kd=this.td*this.kp; + if(super.sZeros==null)super.sZeros = Complex.oneDarray(1); + super.sNumer.resetCoeff(1, new Complex(this.kd, 0.0D)); + super.sZeros[0].reset(-this.kp/this.kd, 0.0D); + super.addDeadTimeExtras(); + } + + // Get the proprtional gain + public double getKp(){ + return this.kp; + } + + // Get the derivative gain + public double getKd(){ + return this.kd; + } + + // Get the derivative time constant + public double getTd(){ + return this.td; + } + + // Perform z transform using an already set delta T + public void zTransform(){ + if(super.deltaT==0.0D)System.out.println("z-transform attempted in PropDeriv with a zero sampling period"); + super.deadTimeWarning("zTransform"); + if(ztransMethod==0){ + this.mapstozAdHoc(); + } + else{ + super.zNumerDeg = 1; + super.zDenomDeg = 1; + super.zNumer = new ComplexPoly(-this.kd, this.kp*super.deltaT + this.kd); + super.zDenom = new ComplexPoly(0.0D, super.deltaT); + super.zZeros = Complex.oneDarray(1); + super.zZeros[0].reset(this.kd/(this.kp*super.deltaT + this.kd),0.0D); + super.zPoles = Complex.oneDarray(1); + super.zPoles[0].reset(0.0D, 0.0D); + } + } + + // Perform z transform setting delta T + public void zTransform(double deltaT){ + super.deltaT=deltaT; + super.deadTimeWarning("zTransform"); + zTransform(); + } + + // Plots the time course for a step input + public void stepInput(double stepMag, double finalTime){ + + // Calculate time course outputs + int n = 51; // number of points on plot + double incrT = finalTime/(double)(n-2); // plotting increment + double cdata[][] = new double [2][n]; // plotting array + + cdata[0][0]=0.0D; + cdata[1][0]=0.0D; + for(int i=2; i<n; i++){ + cdata[0][i]=cdata[0][i-1]+incrT; + } + double kpterm = this.kp*stepMag; + cdata[1][0]=0.0D; + for(int i=1; i<n; i++){ + cdata[1][i] = kpterm; + } + if(super.deadTime!=0.0D)for(int i=0; i<n; i++)cdata[0][i] += super.deadTime; + + // Plot + PlotGraph pg = new PlotGraph(cdata); + + pg.setGraphTitle("Step Input Transient: Step magnitude = "+stepMag); + pg.setGraphTitle2(this.getName()); + pg.setXaxisLegend("Time"); + pg.setXaxisUnitsName("s"); + pg.setYaxisLegend("Output"); + pg.setPoint(0); + pg.setLine(3); + pg.plot(); + } + + // Plots the time course for a unit step input + public void stepInput(double finalTime){ + this.stepInput(1.0D, finalTime); + } + + // Plots the time course for an nth order ramp input (at^n) + public void rampInput(double rampGradient, int rampOrder, double finalTime){ + + if(rampOrder==0){ + // Check if really a step input (rampOrder, n = 0) + this.stepInput(rampGradient, finalTime); + } + else{ + // Calculate time course outputs + int n = 50; // number of points on plot + double incrT = finalTime/(double)(n-1); // plotting increment + double cdata[][] = new double [2][n]; // plotting array + double sum = 0.0D; // integration sum + + cdata[0][0]=0.0D; + cdata[1][0]=0.0D; + for(int i=1; i<n; i++){ + cdata[0][i]=cdata[0][i-1]+incrT; + cdata[1][i] = rampGradient*Math.pow(cdata[0][i],rampOrder-1)*(this.kp*cdata[0][i] + this.kd); + } + if(super.deadTime!=0.0D)for(int i=0; i<n; i++)cdata[0][i] += super.deadTime; + + + // Plot + PlotGraph pg = new PlotGraph(cdata); + + pg.setGraphTitle("Ramp (a.t^n) Input Transient: ramp gradient (a) = "+rampGradient + " ramp order (n) = " + rampOrder); + pg.setGraphTitle2(this.getName()); + pg.setXaxisLegend("Time"); + pg.setXaxisUnitsName("s"); + pg.setYaxisLegend("Output"); + pg.setPoint(0); + pg.plot(); + } + } + + // Plots the time course for an nth order ramp input (t^n) + public void rampInput(int rampOrder, double finalTime){ + double rampGradient = 1.0D; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Plots the time course for a first order ramp input (at) + public void rampInput(double rampGradient, double finalTime){ + int rampOrder = 1; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Plots the time course for a unit ramp input (t) + public void rampInput(double finalTime){ + double rampGradient = 1.0D; + int rampOrder = 1; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Get the s-domain output for a given s-value and a given input. + public Complex getOutputS(Complex sValue, Complex iinput){ + super.sValue=sValue; + super.inputS=iinput; + Complex term = this.sValue.times(this.kd); + term = term.plus(this.kp); + super.outputS=term.times(super.inputS); + if(super.deadTime!=0.0D)super.outputS = super.outputS.times(Complex.exp(super.sValue.times(-super.deadTime))); + return super.outputS; + } + + // Get the s-domain output for the stored input and s-value. + public Complex getOutputS(){ + Complex term = this.sValue.times(this.kd); + term = term.plus(this.kp); + super.outputS=term.times(super.inputS); + if(super.deadTime!=0.0D)super.outputS = super.outputS.times(Complex.exp(super.sValue.times(-super.deadTime))); + return super.outputS; + } + + // Calculate the current time domain output for a given input and given time + // resets deltaT + public void calcOutputT(double ttime, double inp){ + if(ttime<=time[this.sampLen-1])throw new IllegalArgumentException("Current time equals or is less than previous time"); + super.deltaT = ttime - super.time[this.sampLen-1]; + super.sampFreq = 1.0D/super.deltaT; + super.deadTimeWarning("calcOutputT(time, input)"); + for(int i=0; i<super.sampLen-2; i++){ + super.time[i]=super.time[i+1]; + super.inputT[i]=super.inputT[i+1]; + super.outputT[i]=super.outputT[i+1]; + } + super.time[super.sampLen-1]=ttime; + super.inputT[super.sampLen-1]=inp; + super.outputT[super.sampLen-1]=Double.NaN; + this.calcOutputT(); + } + + // Get the output for the stored sampled input, time and deltaT. + public void calcOutputT(){ + // proportional term + super.outputT[super.sampLen-1] = this.kp*super.inputT[sampLen-1]; + // + derivative term + super.outputT[super.sampLen-1] += this.kd*(super.inputT[super.sampLen-1]-super.inputT[super.sampLen-2])/super.deltaT; + } + + // Get the s-domain poles + public Complex[] getSpoles(){ + System.out.println("PD controller has no s-domain poles"); + return null; + } + // Deep copy + public PropDeriv copy(){ + if(this==null){ + return null; + } + else{ + PropDeriv bb = new PropDeriv(); + this.copyBBvariables(bb); + + bb.kp = this.kp; + bb.td = this.td; + bb.kd = this.kd; + + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/control/PropInt.java b/src/main/java/flanagan/control/PropInt.java new file mode 100755 index 0000000000000000000000000000000000000000..107e4f522cda2fcabbd53d431f84e36b8c125142 --- /dev/null +++ b/src/main/java/flanagan/control/PropInt.java @@ -0,0 +1,348 @@ +/* Class PropInt +* +* This class contains the constructor to create an instance of +* a proportional plus integral(PI) controller and +* the methods needed to use this controller in control loops in the +* time domain, Laplace transform s domain or the z-transform z domain. +* +* This class is a subclass of the superclass BlackBox. +* +* Author: Michael Thomas Flanagan. +* +* Created: August 2002 +* Updated: 17 April 2003, 3 May 2005, 2 July 2006, 27 February 2008, 6 April 2008, 7 November 2009 +* +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/PropInt.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + + +package flanagan.control; +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; +import flanagan.plot.Plot; +import flanagan.plot.PlotGraph; + +public class PropInt extends BlackBox{ + private double kp = 1.0D; // proportional gain + private double ti = Double.POSITIVE_INFINITY; // integral time constant + private double ki = 0.0D; // integral gain + + // Constructor - unit proportional gain, zero integral gain + public PropInt(){ + super("PropInt"); + super.setSnumer(new ComplexPoly(0.0D, 1.0D)); + super.setSdenom(new ComplexPoly(0.0D, 1.0D)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + } + + // Set the proportional gain + public void setKp(double kp){ + super.sNumer.resetCoeff(1, new Complex(kp, 0.0)); + super.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + // Set the integral gain + public void setKi(double ki){ + this.ki=ki; + this.ti=this.kp/ki; + super.sNumer.resetCoeff(0, new Complex(ki, 0.0)); + super.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + + // Set the integral time constant + public void setTi(double ti){ + this.ti=ti; + this.ki=this.kp/ti; + super.sNumer.resetCoeff(0, new Complex(ki, 0.0)); + super.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + // Get the proprtional gain + public double getKp(){ + return this.kp; + } + + // Get the integral gain + public double getKi(){ + return this.ki; + } + + // Get the integral time constant + public double getTi(){ + return this.ti; + } + + + // Perform z transform using an already set delta T + public void zTransform(){ + super.deadTimeWarning("zTransform"); + if(super.deltaT==0.0D)System.out.println("z-transform attempted in PropInt with a zero sampling period"); + if(super.ztransMethod==0){ + this.mapstozAdHoc(); + } + else{ + super.zDenom = new ComplexPoly(1); + Complex[] coef = Complex.oneDarray(2); + coef[0].reset(-1.0D,0.0D); + coef[1].reset(1.0D,0.0D); + super.zDenom.resetPoly(coef); + Complex[] zPoles = Complex.oneDarray(1); + zPoles[0].reset(1.0D, 0.0D); + super.zNumer = new ComplexPoly(1); + Complex[] zZeros = Complex.oneDarray(1); + double kit = this.ki*super.deltaT; + switch(this.integMethod){ + // trapezium rule + case 0: coef[0].reset(kit/2.0D - this.kp, 0.0D); + coef[1].reset(kit/2.0D + this.kp, 0.0D); + super.zNumer.resetPoly(coef); + zZeros[0].reset((this.kp - kit/2.0D)/(this.kp + kit/2.0D), 0.0D); + break; + // backward rectangular rule + case 1: coef[0].reset(-this.kp, 0.0D); + coef[1].reset(kit + this.kp, 0.0D); + super.zNumer.resetPoly(coef); + zZeros[0].reset(this.kp/(this.kp + kit), 0.0D); + break; + // foreward rectangular rule + case 2: coef[0].reset(this.kp - kit, 0.0D); + coef[1].reset(this.kp, 0.0D); + super.zNumer.resetPoly(coef); + zZeros[0].reset((this.kp - kit)/this.kp, 0.0D); + break; + default: System.out.println("Integration method option in PropInt must be 0,1 or 2"); + System.out.println("It was set at "+integMethod); + System.out.println("z-transform not performed"); + } + } + } + + // Perform z transform setting delta T + public void zTransform(double deltaT){ + super.deltaT=deltaT; + zTransform(); + } + + // Plots the time course for a step input + public void stepInput(double stepMag, double finalTime){ + + // Calculate time course outputs + int n = 50; // number of points on plot + double incrT = finalTime/(double)(n-1); // plotting increment + double cdata[][] = new double [2][n]; // plotting array + double sum = 0.0D; // integration sum + + cdata[0][0]=0.0D; + for(int i=1; i<n; i++){ + cdata[0][i]=cdata[0][i-1]+incrT; + } + double kpterm = this.kp*stepMag; + for(int i=0; i<n; i++){ + sum += ki*incrT*stepMag; + cdata[1][i] = kpterm + sum; + cdata[0][i] += super.deadTime; + } + + // Plot + PlotGraph pg = new PlotGraph(cdata); + + pg.setGraphTitle("Step Input Transient: Step magnitude = "+stepMag); + pg.setGraphTitle2(this.getName()); + pg.setXaxisLegend("Time"); + pg.setXaxisUnitsName("s"); + pg.setYaxisLegend("Output"); + pg.setPoint(0); + pg.plot(); + } + + // Plots the time course for a unit step input + public void stepInput(double finalTime){ + this.stepInput(1.0D, finalTime); + } + + // Plots the time course for an nth order ramp input (at^n) + public void rampInput(double rampGradient, int rampOrder, double finalTime){ + + // Calculate time course outputs + int n = 50; // number of points on plot + double incrT = finalTime/(double)(n-1); // plotting increment + double cdata[][] = new double [2][n]; // plotting array + double sum = 0.0D; // integration sum + + cdata[0][0]=0.0D; + cdata[1][0]=0.0D; + for(int i=1; i<n; i++){ + cdata[0][i]=cdata[0][i-1]+incrT; + sum += rampGradient*(Math.pow(cdata[0][i],rampOrder+1) - Math.pow(cdata[0][i-1],rampOrder+1))/(double)(rampOrder+1); + cdata[1][i] = this.kp*rampGradient*Math.pow(cdata[0][i],rampOrder) + sum; + } + for(int i=0; i<n; i++){ + cdata[0][i] += super.deadTime; + } + + // Plot + PlotGraph pg = new PlotGraph(cdata); + + pg.setGraphTitle("Ramp (a.t^n) Input Transient: ramp gradient (a) = "+rampGradient + " ramp order (n) = " + rampOrder); + pg.setGraphTitle2(this.getName()); + pg.setXaxisLegend("Time"); + pg.setXaxisUnitsName("s"); + pg.setYaxisLegend("Output"); + pg.setPoint(0); + pg.plot(); + } + + // Plots the time course for an nth order ramp input (t^n) + public void rampInput(int rampOrder, double finalTime){ + double rampGradient = 1.0D; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Plots the time course for a first order ramp input (at) + public void rampInput(double rampGradient, double finalTime){ + int rampOrder = 1; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Plots the time course for a unit ramp input (t) + public void rampInput(double finalTime){ + double rampGradient = 1.0D; + int rampOrder = 1; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Get the s-domain output for a given s-value and a given input. + public Complex getOutputS(Complex sValue, Complex iinput){ + super.sValue=sValue; + super.inputS=iinput; + Complex term = super.sValue.times(this.kp); + term = term.plus(this.ki); + term = term.over(super.sValue); + super.outputS=term.times(super.inputS); + if(super.deadTime!=0.0D)super.outputS = super.outputS.times(Complex.exp(super.sValue.times(-super.deadTime))); + return super.outputS; + } + + // Get the s-domain output for the stored input and s-value. + public Complex getOutputS(){ + Complex term = super.sValue.times(this.kp); + term = term.plus(this.ki); + term = term.over(super.sValue); + super.outputS=term.times(super.inputS); + if(super.deadTime!=0.0D)super.outputS = super.outputS.times(Complex.exp(super.sValue.times(-super.deadTime))); + return super.outputS; + } + + // Calculate the current time domain output for a given input and given time + // resets deltaT + public void calcOutputT(double ttime, double inp){ + if(ttime<=time[this.sampLen-1])throw new IllegalArgumentException("Current time equals or is less than previous time"); + super.deltaT = ttime - super.time[this.sampLen-1]; + super.sampFreq = 1.0D/super.deltaT; + super.deadTimeWarning("calcOutputT(time, input)"); + for(int i=0; i<super.sampLen-2; i++){ + super.time[i]=super.time[i+1]; + super.inputT[i]=super.inputT[i+1]; + super.outputT[i]=super.outputT[i+1]; + } + super.time[super.sampLen-1]=ttime; + super.inputT[super.sampLen-1]=inp; + super.outputT[super.sampLen-1]=Double.NaN; + this.calcOutputT(); + } + + // calculate the output for the stored sampled input and time. + public void calcOutputT(){ + super.deadTimeWarning("calcOutputT()"); + // proportional term + super.outputT[super.sampLen-1]=this.kp*super.inputT[super.sampLen-1]; + // + integral term + if(super.forgetFactor==1.0D){ + switch(super.integMethod){ + // trapezium Rule + case 0: super.integrationSum += (super.inputT[super.sampLen-1]+super.inputT[super.sampLen-2])*super.deltaT/2.0D; + break; + // backward rectangular rule + case 1: super.integrationSum += super.inputT[super.sampLen-1]*super.deltaT; + break; + // foreward rectangular rule + case 2: super.integrationSum += super.inputT[super.sampLen-2]*super.deltaT; + break; + default: System.out.println("Integration method option in PropInt must be 0,1 or 2"); + System.out.println("It was set at "+super.integMethod); + System.out.println("getOutput not performed"); + } + } + else{ + switch(super.integMethod){ + // trapezium Rule + case 0: super.integrationSum=0.0D; + for(int i=1; i<super.sampLen; i++){ + super.integrationSum+=Math.pow(super.forgetFactor, super.sampLen-1-i)*(super.inputT[i-1]+super.inputT[i])*super.deltaT/2.0D; + }; + break; + // backward rectangular rule + case 1: super.integrationSum=0.0D; + for(int i=1; i<sampLen; i++){ + super.integrationSum+=Math.pow(super.forgetFactor, super.sampLen-1-i)*(super.inputT[i])*super.deltaT; + }; + break; + // foreward rectangular rule + case 2: super.integrationSum=0.0D; + for(int i=1; i<super.sampLen; i++){ + super.integrationSum+=Math.pow(super.forgetFactor, super.sampLen-1-i)*(super.inputT[i-1])*super.deltaT; + }; + break; + default: System.out.println("Integration method option in PropInt must be 0,1 or 2"); + System.out.println("It was set at "+super.integMethod); + System.out.println("getOutput not performed"); + } + } + super.outputT[super.sampLen-1] += this.ki*super.integrationSum; + } + + + // Deep copy + public PropInt copy(){ + if(this==null){ + return null; + } + else{ + PropInt bb = new PropInt(); + this.copyBBvariables(bb); + + bb.kp = this.kp; + bb.ti = this.ti; + bb.ki = this.ki; + + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} diff --git a/src/main/java/flanagan/control/PropIntDeriv.java b/src/main/java/flanagan/control/PropIntDeriv.java new file mode 100755 index 0000000000000000000000000000000000000000..000c9db5daa31f75c1a27c3154ce8cb420d8b63c --- /dev/null +++ b/src/main/java/flanagan/control/PropIntDeriv.java @@ -0,0 +1,411 @@ +/* Class PropIntDeriv +* +* This class contains the constructor to create an instance of +* a proportional plus integral plus Derivative (PID) controller and +* the methods needed to use this controller in control loops in the +* time domain, Laplace transform s domain or the z-transform z domain. +* +* This class is a subclass of the superclass BlackBox. +* +* Author: Michael Thomas Flanagan. +* +* Created: August 2002 +* Updated: 17 April 2003, 3 May 2005, 2 July 2006, 27 February 2008, 6 April 2008, 7 November 2009 +* +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/PropIntDeriv.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + + +package flanagan.control; +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; +import flanagan.plot.Plot; +import flanagan.plot.PlotGraph; + + +public class PropIntDeriv extends BlackBox{ + private double kp = 1.0D; // proportional gain + private double ti = Double.POSITIVE_INFINITY; // integral time constant + private double ki = 0.0D; // integral gain + private double td = 0.0D; // derivative time constant + private double kd = 0.0D; // derivative gain + + // Constructor - unit proportional gain, zero integral gain, zero derivative gain + public PropIntDeriv(){ + super("PropIntDeriv"); + super.setSnumer(new ComplexPoly(0.0D, 1.0D, 0.0D)); + super.setSdenom(new ComplexPoly(0.0D, 1.0D)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + } + + // Set the proportional gain + public void setKp(double kp){ + this.kp=kp; + super.sNumer.resetCoeff(1, new Complex(kp, 0.0)); + super.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + // Set the integral gain + public void setKi(double ki){ + this.ki=ki; + this.ti=this.kp/ki; + super.sNumer.resetCoeff(0, new Complex(ki, 0.0)); + super.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + // Set the integral time constant + public void setTi(double ti){ + this.ti=ti; + this.ki=this.kp/ti; + super.sNumer.resetCoeff(0, new Complex(ki, 0.0)); + super.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + // Set the derivative gain + public void setKd(double kd){ + this.kd=kd; + this.td=kd/this.kp; + super.sNumer.resetCoeff(2, new Complex(kd, 0.0)); + super.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + // Set the derivative time constant + public void setTd(double td){ + this.td=td; + this.kd=this.kp*td; + super.sNumer.resetCoeff(2, new Complex(kd, 0.0)); + super.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + // Get the proprtional gain + public double getKp(){ + return this.kp; + } + + // Get the integral gain + public double getKi(){ + return this.ki; + } + + // Get the integral time constant + public double getTi(){ + return this.ti; + } + + // Get the derivative gain + public double getKd(){ + return this.kd; + } + + // Get the derivative time constant + public double getTd(){ + return this.td; + } + + // Perform z transform using an already set delta T + public void zTransform(){ + if(super.deltaT==0.0D)System.out.println("z-transform attempted in PropIntDeriv with a zero sampling period"); + super.deadTimeWarning("zTransform"); + if(super.ztransMethod==0){ + this.mapstozAdHoc(); + } + else{ + double kit = this.ki*super.deltaT; + double kdt = this.kd/super.deltaT; + Complex[] coef = Complex.oneDarray(3); + coef[0].reset(0.0D,0.0D); + coef[1].reset(-1.0D,0.0D); + coef[2].reset(1.0D,0.0D); + super.zDenom.resetPoly(coef); + switch(this.integMethod){ + // Trapezium rule + case 0: coef[0].reset(kdt,0.0D); + coef[1].reset(kit/2.0D-2.0D*kdt-this.kp,0.0D); + coef[2].reset(this.kp+kit/2.0D+kdt,0.0); + super.zNumer.resetPoly(coef); + break; + // Backward rectangular rule + case 1: coef[0].reset(kdt,0.0D); + coef[1].reset(-2.0D*kdt-this.kp,0.0D); + coef[2].reset(this.kp+kit+kdt,0.0); + super.zNumer.resetPoly(coef); + break; + // Foreward tectangular rule + case 2: coef[0].reset(kdt,0.0D); + coef[1].reset(kit-2.0D*kdt-this.kp,0.0D); + coef[2].reset(this.kp+kdt,0.0); + super.zNumer.resetPoly(coef); + break; + default: System.out.println("Integration method option in PropIntDeriv must be 0,1 or 2"); + System.out.println("It was set at "+integMethod); + System.out.println("z-transform not performed"); + } + } + super.zZeros = super.zNumer.roots(); + super.zPoles = super.zDenom.roots(); + } + + // Perform z transform setting delta T + public void zTransform(double deltaT){ + super.deltaT=deltaT; + this.zTransform(); + } + + // Calculate the pole and the zero in the z-domain for an already set sampling period + public void calcPolesZerosZ(){ + if(super.deltaT==0.0D)System.out.println("z-pole and z-zero calculation attempted in PropIntDeriv.calcPolesZerosZ( with a zero sampling period"); + this.zTransform(); + super.zPoles[0].reset(0.0D, 0.0D); + super.zPoles[1].reset(1.0D, 0.0D); + super.zZeros = super.zNumer.roots(); + } + + // Calculate the pole and the zero in the z-domain setting the sampling period + public void calcPolesZerosZ(double deltaT){ + this.deltaT = deltaT; + this.calcPolesZerosZ(); + } + + // Plots the time course for a step input + public void stepInput(double stepMag, double finalTime){ + + // Calculate time course outputs + int n = 50; // number of points on plot + double incrT = finalTime/(double)(n-1); // plotting increment + double cdata[][] = new double [2][n]; // plotting array + double sum = 0.0D; // integration sum + + cdata[0][0]=0.0D; + for(int i=1; i<n; i++){ + cdata[0][i]=cdata[0][i-1]+incrT; + } + double kpterm = this.kp*stepMag; + for(int i=0; i<n; i++){ + sum += ki*incrT*stepMag; + cdata[1][i] = kpterm + sum; + } + if(super.deadTime!=0.0D)for(int i=0; i<n; i++)cdata[0][i] += super.deadTime; + + // Plot + PlotGraph pg = new PlotGraph(cdata); + + pg.setGraphTitle("Step Input Transient: Step magnitude = "+stepMag); + pg.setGraphTitle2(this.getName()); + pg.setXaxisLegend("Time"); + pg.setXaxisUnitsName("s"); + pg.setYaxisLegend("Output"); + pg.setPoint(0); + pg.plot(); + } + + // Plots the time course for a unit step input + public void stepInput(double finalTime){ + this.stepInput(1.0D, finalTime); + } + + // Plots the time course for an nth order ramp input (at^n) + public void rampInput(double rampGradient, int rampOrder, double finalTime){ + + // Check if really a step input + if(rampOrder==0){ + this.stepInput(rampGradient, finalTime); + } + else{ + // Calculate time course outputs + int n = 50; // number of points on plot + double incrT = finalTime/(double)(n-1); // plotting increment + double cdata[][] = new double [2][n]; // plotting array + double sum = 0.0D; // integration sum + + cdata[0][0]=0.0D; + cdata[1][0]=0.0D; + for(int i=1; i<n; i++){ + cdata[0][i]=cdata[0][i-1]+incrT; + sum += ki*rampGradient*(Math.pow(cdata[0][i],rampOrder+1) - Math.pow(cdata[0][i-1],rampOrder+1))/(double)(rampOrder+1); + cdata[1][i] = this.kp*rampGradient*Math.pow(cdata[0][i],rampOrder) + sum; + } + if(super.deadTime!=0.0D)for(int i=0; i<n; i++)cdata[0][i] += super.deadTime; + + // Plot + PlotGraph pg = new PlotGraph(cdata); + + pg.setGraphTitle("Ramp (a.t^n) Input Transient: ramp gradient (a) = "+rampGradient + " ramp order (n) = " + rampOrder); + pg.setGraphTitle2(this.getName()); + pg.setXaxisLegend("Time"); + pg.setXaxisUnitsName("s"); + pg.setYaxisLegend("Output"); + pg.setPoint(0); + pg.plot(); + } + } + + // Plots the time course for an nth order ramp input (t^n) + public void rampInput(int rampOrder, double finalTime){ + double rampGradient = 1.0D; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Plots the time course for a first order ramp input (at) + public void rampInput(double rampGradient, double finalTime){ + int rampOrder = 1; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Plots the time course for a unit ramp input (t) + public void rampInput(double finalTime){ + double rampGradient = 1.0D; + int rampOrder = 1; + this.rampInput(rampGradient, rampOrder, finalTime); + } + + // Get the s-domain output for a given s-value and a given input. + public Complex getOutputS(Complex sValue, Complex iinput){ + super.sValue = sValue; + super.inputS = iinput; + Complex term1 = Complex.plusOne(); + Complex term2 = Complex.plusOne(); + Complex term3 = Complex.plusOne(); + term1 = term1.times(this.kp); + term2 = term2.times(this.ki); + term2 = term2.over(this.sValue); + term3 = term3.times(this.kd); + term3 = term3.times(super.sValue); + Complex term = term1.plus(term2.plus(term3)); + super.outputS = term.times(super.inputS); + if(super.deadTime!=0.0D)super.outputS = super.outputS.times(Complex.exp(super.sValue.times(-super.deadTime))); + return super.outputS; } + + // Get the s-domain output for the stored input and s-value. + public Complex getOutputS(){ + Complex term1 = Complex.plusOne(); + Complex term2 = Complex.plusOne(); + Complex term3 = Complex.plusOne(); + term1 = term1.times(this.kp); + term2 = term2.times(this.ki); + term2 = term2.over(this.sValue); + term3 = term3.times(this.kd); + term3 = term3.times(super.sValue); + Complex term = term1.plus(term2.plus(term3)); + super.outputS = term.times(super.inputS); + if(super.deadTime!=0.0D)super.outputS = super.outputS.times(Complex.exp(super.sValue.times(-super.deadTime))); + return super.outputS; + } + + + // Calculate the current time domain output for a given input and given time + // resets deltaT + public void calcOutputT(double ttime, double inp){ + if(ttime<=time[this.sampLen-1])throw new IllegalArgumentException("Current time equals or is less than previous time"); + super.deltaT = ttime - super.time[this.sampLen-1]; + super.sampFreq = 1.0D/super.deltaT; + super.deadTimeWarning("zTransform"); + for(int i=0; i<super.sampLen-2; i++){ + super.time[i]=super.time[i+1]; + super.inputT[i]=super.inputT[i+1]; + super.outputT[i]=super.outputT[i+1]; + } + super.time[super.sampLen-1]=ttime; + super.inputT[super.sampLen-1]=inp; + super.outputT[super.sampLen-1]=Double.NaN; + this.calcOutputT(); + } + + // Calculate the output for the stored sampled input and time + public void calcOutputT(){ + super.deadTimeWarning("zTransform"); + // proportional term + super.outputT[super.sampLen-1]=this.kp*super.inputT[super.sampLen-1]; + // + integral term + if(super.forgetFactor==1.0D){ + switch(super.integMethod){ + // trapezium Rule + case 0: super.integrationSum += (super.inputT[super.sampLen-1]+super.inputT[super.sampLen-2])*super.deltaT/2.0D; + break; + // backward rectangular rule + case 1: super.integrationSum += super.inputT[super.sampLen-1]*super.deltaT; + break; + // foreward rectangular rule + case 2: super.integrationSum += super.inputT[super.sampLen-2]*super.deltaT; + break; + default: System.out.println("Integration method option in PropInt must be 0,1 or 2"); + System.out.println("It was set at "+super.integMethod); + System.out.println("getOutput not performed"); + } + } + else{ + switch(super.integMethod){ + // trapezium Rule + case 0: super.integrationSum=0.0D; + for(int i=1; i<super.sampLen; i++){ + super.integrationSum+=Math.pow(super.forgetFactor, super.sampLen-1-i)*(super.inputT[i-1]+super.inputT[i])*super.deltaT/2.0D; + }; + break; + // backward rectangular rule + case 1: super.integrationSum=0.0D; + for(int i=1; i<sampLen; i++){ + super.integrationSum+=Math.pow(super.forgetFactor, super.sampLen-1-i)*(super.inputT[i])*super.deltaT; + }; + break; + // foreward rectangular rule + case 2: super.integrationSum=0.0D; + for(int i=1; i<super.sampLen; i++){ + super.integrationSum+=Math.pow(super.forgetFactor, super.sampLen-1-i)*(super.inputT[i-1])*super.deltaT; + }; + break; + default: System.out.println("Integration method option in PropInt must be 0,1 or 2"); + System.out.println("It was set at "+super.integMethod); + System.out.println("getOutput not performed"); + } + } + super.outputT[super.sampLen-1] += this.ki*super.integrationSum; + // + derivative term + super.outputT[sampLen-1] += this.kd*(super.inputT[sampLen-1]-super.inputT[sampLen-2])/super.deltaT; + } + + + // Deep copy + public PropIntDeriv copy(){ + if(this==null){ + return null; + } + else{ + PropIntDeriv bb = new PropIntDeriv(); + this.copyBBvariables(bb); + + bb.kp = this.kp; + bb.ti = this.ti; + bb.td = this.td; + bb.kd = this.kd; + + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} diff --git a/src/main/java/flanagan/control/SecondOrder.java b/src/main/java/flanagan/control/SecondOrder.java new file mode 100755 index 0000000000000000000000000000000000000000..ade418f61f9f294911b125e04a53e77f0198b0c2 --- /dev/null +++ b/src/main/java/flanagan/control/SecondOrder.java @@ -0,0 +1,403 @@ +/* Class SecondOrder +* +* This class contains the constructor to create an instance of +* a second order process, +* a.d^2(output)/dt^2 + b.d(output)/dt + c.output = d.input +* and the methods needed to use this process in simulation +* of control loops. +* +* This class is a subclass of the superclass BlackBox. +* +* Author: Michael Thomas Flanagan. +* +* Created: March 2003 +* Updated: 23 April 2003, 3 May 2005, 3 April 2006, 2 July 2006, 6 April 2008, 2-7 November 2009 +* +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/SecondOrder.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + + +package flanagan.control; +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; + +public class SecondOrder extends BlackBox{ + + private double aConst = 1.0D; // a constant in differential equation above + private double bConst = 1.0D; // b constant in differential equation above + private double cConst = 1.0D; // c constant in differential equation above + private double dConst = 1.0D; // d constant in differential equation above + private double omegaN = 1.0D; // undamped natural frequency (resonant frequency) + private double zeta = 1.0D; // damping ratio + private double kConst = 1.0D; // the standard form gain constant + private double sigma = 1.0D; // attenuation (zeta*omegaN) + + // Constructor + // Sets all constants to unity + public SecondOrder(){ + super("SecondOrder"); + super.setSnumer(new ComplexPoly(1.0D)); + super.setSdenom(new ComplexPoly(1.0D, 1.0D, 1.0D)); + super.sNumerDeg = 0; + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + } + + // Constructor + // within constants set from argument list + public SecondOrder(double aa, double bb, double cc, double dd){ + super("SecondOrder"); + this.aConst = aa; + this.bConst = bb; + this.cConst = cc; + this.dConst = dd; + if(this.cConst>0.0D)this.standardForm(); + super.setSnumer(new ComplexPoly(this.dConst)); + super.setSdenom(new ComplexPoly(this.cConst, this.bConst, this.aConst)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + } + + // Set a, b, c and d + public void setCoeff(double aa, double bb, double cc, double dd){ + this.aConst = aa; + this.bConst = bb; + this.cConst = cc; + this.dConst = dd; + if(this.cConst>0.0D)this.standardForm(); + Complex[] num = Complex.oneDarray(1); + num[0].reset(this.dConst, 0.0); + super.sNumer.resetPoly(num); + Complex[] den = Complex.oneDarray(3); + den[0].reset(this.cConst, 0.0); + den[1].reset(this.bConst, 0.0); + den[2].reset(this.aConst, 0.0); + super.sDenom.resetPoly(den); + super.fixedName = "Second Order Process"; + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + // Private method for setting the contants of the natural frequency standard form + private void standardForm(){ + this.omegaN = Math.sqrt(this.cConst/this.aConst); + this.zeta = this.bConst/(2.0D*this.aConst*this.omegaN); + this.kConst = this.dConst/this.cConst; + this.sigma = this.zeta*this.omegaN; + } + + public void setA(double aa){ + this.aConst = aa; + Complex co = new Complex(this.aConst, 0.0); + super.sDenom.resetCoeff(2, co); + if(this.cConst>0.0D)this.standardForm(); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setB(double bb){ + this.bConst = bb; + Complex co = new Complex(this.bConst, 0.0); + super.sDenom.resetCoeff(1, co); + if(this.cConst>0.0D)this.standardForm(); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setC(double cc){ + this.cConst = cc; + Complex co = new Complex(this.cConst, 0.0); + super.sDenom.resetCoeff(0, co); + if(this.cConst>0.0D)this.standardForm(); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setD(double dd){ + this.dConst = dd; + Complex co = new Complex(this.dConst, 0.0); + super.sNumer.resetCoeff(0, co); + if(this.cConst>0.0D)this.standardForm(); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setStandardForm(double zet, double omega, double kk){ + if(omega<=0)throw new IllegalArgumentException("zero or negative natural frequency"); + if(zet<0)throw new IllegalArgumentException("negative damping ratio"); + this.zeta = zet; + this.omegaN = omega; + this.kConst = kk; + this.sigma = this.omegaN*this.zeta; + this.reverseStandard(); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setZeta(double zet){ + if(zet<0)throw new IllegalArgumentException("negative damping ratio"); + this.zeta = zet; + this.sigma = this.omegaN*this.zeta; + this.reverseStandard(); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setOmegaN(double omega){ + if(omega<=0)throw new IllegalArgumentException("zero or negative natural frequency"); + this.omegaN = omega; + this.sigma = this.omegaN*this.zeta; + this.reverseStandard(); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setK(double kk){ + this.kConst = kk; + this.reverseStandard(); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + // Private method for obtaining a, b c and d from zeta, omegan and k + private void reverseStandard(){ + this.aConst = this.omegaN*this.omegaN; + this.bConst = 2.0D*this.zeta*this.omegaN; + this.cConst = 1.0D; + this.dConst = this.kConst*this.aConst; + Complex[] num = Complex.oneDarray(1); + num[0].reset(this.dConst, 0.0); + super.sNumer.resetPoly(num); + Complex[] den = Complex.oneDarray(3); + den[0].reset(this.cConst, 0.0); + den[1].reset(this.bConst, 0.0); + den[2].reset(this.aConst, 0.0); + super.sDenom.resetPoly(den); + } + + public double getA(){ + return this.aConst; + } + + public double getB(){ + return this.bConst; + } + + public double getC(){ + return this.cConst; + } + + public double getD(){ + return this.dConst; + } + + public double getOmegaN(){ + return this.omegaN; + } + + public double getZeta(){ + return this.zeta; + } + + public double getK(){ + return this.kConst; + } + + public double getAttenuation(){ + return this.sigma; + } + + // Calculate the zeros and poles in the s-domain + protected void calcPolesZerosS(){ + super.sPoles = super.sDenom.roots(); + if(super.sDenomSet)super.sDenomScaleFactor = BlackBox.scaleFactor( super.sDenom, super.sPoles); + if(super.sNumerSet)super.sNumerScaleFactor = super.sNumer.coeffCopy(0); + + } + + // Get the s-domain output for a given s-value and a given input. + public Complex getOutputS(Complex sValue, Complex iinput){ + super.sValue=sValue; + super.inputS=iinput; + return this.getOutputS(); + } + + // Get the s-domain output for the stored input and s-value. + public Complex getOutputS(){ + Complex num = Complex.plusOne(); + num = num.times(this.dConst); + Complex den = new Complex(); + den = this.sValue.times(this.sValue.times(this.aConst)); + den = den.plus(this.sValue.times(this.aConst)); + den = den.plus(this.cConst); + Complex term = new Complex(); + term = num.over(den); + super.outputS = term.times(super.inputS); + if(super.deadTime!=0.0D)super.outputS = super.outputS.times(Complex.exp(super.sValue.times(-super.deadTime))); + return super.outputS; + } + + // Perform z transform using an already set delta T + public void zTransform(){ + if(super.deltaT==0.0D)System.out.println("z-transform attempted in SecondOrder with a zero sampling period"); + if(ztransMethod==0){ + this.mapstozAdHoc(); + } + else{ + Complex[] ncoef = null; + Complex[] dcoef = null; + double bT = this.bConst*this.deltaT; + double t2 = this.deltaT*this.deltaT; + double cT2 = this.cConst*t2; + double dT2 = this.dConst*t2; + switch(this.integMethod){ + // Trapezium Rule + case 0: ncoef = Complex.oneDarray(3); + ncoef[0].reset(dT2/4.0D, 0.0D); + ncoef[1].reset(dT2/2.0D, 0.0D); + ncoef[2].reset(dT2/4.0D, 0.0D); + super.zNumer=new ComplexPoly(2); + super.zNumer.resetPoly(ncoef); + super.zNumerDeg=2; + dcoef = Complex.oneDarray(3); + dcoef[0].reset(this.aConst - bT + cT2/4.0D, 0.0D); + dcoef[1].reset(-2.0D*this.aConst + bT + cT2/2.0D, 0.0D); + dcoef[2].reset(this.aConst + cT2/4.0D, 0.0D); + super.zDenom=new ComplexPoly(2); + super.zDenom.resetPoly(dcoef); + super.zDenomDeg=2; + super.zZeros = zNumer.roots(); + super.zPoles = zDenom.roots(); + break; + // Backward Rectangular Rule + case 1: ncoef = Complex.oneDarray(3); + ncoef[0].reset(0.0D, 0.0D); + ncoef[1].reset(0.0D, 0.0D); + ncoef[2].reset(dT2, 0.0D); + super.zNumer=new ComplexPoly(2); + super.zNumer.resetPoly(ncoef); + super.zNumerDeg=2; + dcoef = Complex.oneDarray(3); + dcoef[0].reset(this.aConst - bT, 0.0D); + dcoef[1].reset(-2.0D*this.aConst, 0.0D); + dcoef[2].reset(this.aConst + bT + cT2, 0.0D); + super.zDenom=new ComplexPoly(2); + super.zDenom.resetPoly(dcoef); + super.zDenomDeg=2; + super.zPoles = zDenom.roots(); + super.zZeros = Complex.oneDarray(2); + super.zZeros[0].reset(0.0D, 0.0D); + super.zZeros[1].reset(0.0D, 0.0D); + break; + // Foreward Rectangular Rule + case 2: ncoef = Complex.oneDarray(3); + ncoef[0].reset(0.0D, 0.0D); + ncoef[1].reset(0.0D, 0.0D); + ncoef[2].reset(dT2, 0.0D); + super.zNumer=new ComplexPoly(2); + super.zNumer.resetPoly(ncoef); + super.zNumerDeg=2; + dcoef = Complex.oneDarray(3); + dcoef[0].reset(this.aConst - bT + cT2, 0.0D); + dcoef[1].reset(-2.0D*this.aConst + bT, 0.0D); + dcoef[2].reset(this.aConst, 0.0D); + super.zDenom=new ComplexPoly(2); + super.zDenom.resetPoly(dcoef); + super.zDenomDeg=2; + super.zPoles = zDenom.roots(); + super.zZeros = Complex.oneDarray(2); + super.zZeros[0].reset(0.0D, 0.0D); + super.zZeros[1].reset(0.0D, 0.0D); + break; + default: System.out.println("Integration method option in SecondOrder must be 0,1 or 2"); + System.out.println("It was set at "+integMethod); + System.out.println("z-transform not performed"); + } + } + } + + // Perform z transform setting delta T + public void zTransform(double deltaT){ + super.deltaT=deltaT; + super.deadTimeWarning("zTransform"); + zTransform(); + } + + // Calculate the current time domain output for a given input and given time + // resets deltaT + public void calcOutputT(double ttime, double inp){ + if(ttime<=time[this.sampLen-1])throw new IllegalArgumentException("Current time equals or is less than previous time"); + super.deltaT = ttime - super.time[this.sampLen-1]; + super.sampFreq = 1.0D/super.deltaT; + super.deadTimeWarning("calcOutputT(time, input)"); + for(int i=0; i<super.sampLen-2; i++){ + super.time[i]=super.time[i+1]; + super.inputT[i]=super.inputT[i+1]; + super.outputT[i]=super.outputT[i+1]; + } + super.time[super.sampLen-1]=ttime; + super.inputT[super.sampLen-1]=inp; + super.outputT[super.sampLen-1]=Double.NaN; + this.calcOutputT(); + } + + // Get the output for the stored sampled input, time and deltaT. + public void calcOutputT(){ + super.outputT[sampLen-1] = (this.cConst*super.inputT[sampLen-1] + this.bConst*(super.inputT[sampLen-1]-super.inputT[sampLen-3])/super.deltaT + this.cConst*(super.inputT[sampLen-1]-2.0D*super.inputT[sampLen-2]+super.inputT[sampLen-3])/(super.deltaT*super.deltaT))/this.dConst; + } + + // Get the s-domain zeros + public Complex[] getSzeros(){ + System.out.println("This standard second order process (class SecondOrder) has no s-domain zeros"); + return null; + } + + // Deep copy + public SecondOrder copy(){ + if(this==null){ + return null; + } + else{ + SecondOrder bb = new SecondOrder(); + this.copyBBvariables(bb); + + bb.aConst = this.aConst; + bb.bConst = this.bConst; + bb.cConst = this.cConst; + bb.dConst = this.dConst; + bb.omegaN = this.omegaN; + bb.zeta = this.zeta; + bb.kConst = this.kConst; + bb.sigma = this.sigma; + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/control/Transducer.java b/src/main/java/flanagan/control/Transducer.java new file mode 100755 index 0000000000000000000000000000000000000000..db1b4f134f5d3b18924051653ffba0fc32d5c276 --- /dev/null +++ b/src/main/java/flanagan/control/Transducer.java @@ -0,0 +1,339 @@ +/* Class Transducer +* +* This class contains the constructor to create an instance of +* a Transducer with a time constant, tConst, and a gain, tGain +* and the methods needed to use this process in simulation +* of control loops. +* +* This class is a subclass of the superclass BlackBox. +* +* Author: Michael Thomas Flanagan. +* +* Created: October 2009 +* Updates: 2-7 November 2009 +* +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Transducer.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + + +package flanagan.control; +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; +import flanagan.plot.*; + +public class Transducer extends BlackBox{ + + private double tGain = 1.0D; // transducer gain + private double tConst = 0.0D; // transducer time constant + private double aConst = 1.0D; // a constant in equivalent first order process + private double bConst = 1.0D; // b constant in equivalent first order process + private double cConst = 0.0D; // c constant in equivalent first order process + + // Constructor + // gain set to 1; time constant set to 0 + public Transducer(){ + super("Transducer"); + super.sPoles = Complex.oneDarray(1); + super.setSnumer(new ComplexPoly(1.0D)); + super.setSdenom(new ComplexPoly(1.0D, 1.0D)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + } + + // Constructor + // within constants set from argument list + public Transducer(double tGain, double tConst){ + super("Transducer"); + this.tGain = tGain; + this.tConst = tConst; + this.aConst = tConst; + this.bConst = 1.0; + this.cConst = tGain; + super.sPoles = Complex.oneDarray(1); + super.setSnumer(new ComplexPoly(this.cConst)); + super.setSdenom(new ComplexPoly(this.bConst, this.aConst)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + } + + // Constructor + // time constant set to zero + public Transducer(double tGain){ + super("Transducer"); + this.tGain = tGain; + this.tConst = 0.0; + this.aConst = 0.0; + this.bConst = 1.0; + this.cConst = tGain; + super.sPoles = Complex.oneDarray(1); + super.setSnumer(new ComplexPoly(this.cConst)); + super.setSdenom(new ComplexPoly(this.bConst, this.aConst)); + super.setZtransformMethod(1); + super.addDeadTimeExtras(); + } + // Set coefficients + public void setCoeff(double tGain, double tConst){ + this.tGain = tGain; + this.tConst = tConst; + this.aConst = tConst; + this.bConst = 1.0; + this.cConst = tGain; + Complex[] num = Complex.oneDarray(1); + num[0].reset(this.cConst, 0.0); + super.sNumer.resetPoly(num); + Complex[] den = Complex.oneDarray(2); + den[0].reset(this.bConst, 0.0); + den[1].reset(this.aConst, 0.0); + super.sDenom.resetPoly(den); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setTimeConstant(double tConst){ + this.tConst = tConst; + this.aConst = tConst; + Complex co = new Complex(this.aConst, 0.0); + super.sDenom.resetCoeff(1, co); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + public void setGain(double tGain){ + this.tGain = tGain; + this.cConst = tGain; + Complex co = new Complex(this.cConst, 0.0); + super.sNumer.resetCoeff(0, co); + this.calcPolesZerosS(); + super.addDeadTimeExtras(); + } + + // Get coefficients + public double getGain(){ + return this.tGain; + } + + public double getTimeConstant(){ + return this.tConst; + } + + // Calculate the zeros and poles in the s-domain + protected void calcPolesZerosS(){ + super.sPoles = Complex.oneDarray(1); + super.sPoles[0].setReal(-bConst/aConst); + super.sNumerScaleFactor = super.sNumer.coeffCopy(0); + super.sNumerScaleFactor = BlackBox.scaleFactor(super.sNumer, super.sPoles); + + } + + + // Plots the time course for a step input + public void stepInput(double stepMag, double finalTime){ + + if(this.tConst==0.0){ + // Calculate time course outputs + int n = 51; // number of points on plot + double incrT = finalTime/(double)(n-2); // plotting increment + double cdata[][] = new double [2][n]; // plotting array + + cdata[0][0]=0.0D; + cdata[0][1]=0.0D; + for(int i=2; i<n; i++){ + cdata[0][i]=cdata[0][i-1]+incrT; + } + double kpterm = this.tGain*stepMag; + cdata[1][0]=0.0D; + for(int i=1; i<n; i++){ + cdata[1][i] = kpterm; + } + if(super.deadTime!=0.0D)for(int i=0; i<n; i++)cdata[0][i] += super.deadTime; + + // Plot + PlotGraph pg = new PlotGraph(cdata); + + pg.setGraphTitle("Step Input Transient: Step magnitude = "+stepMag); + pg.setGraphTitle2(this.getName()); + pg.setXaxisLegend("Time"); + pg.setXaxisUnitsName("s"); + pg.setYaxisLegend("Output"); + pg.setPoint(0); + pg.setLine(3); + pg.plot(); + } + else{ + super.stepInput(stepMag, finalTime); + } + } + + + // Perform z transform using an already set delta T + public void zTransform(){ + if(super.deltaT==0.0D)System.out.println("z-transform attempted in Transducer with a zero sampling period"); + super.deadTimeWarning("zTransform"); + if(ztransMethod==0){ + this.mapstozAdHoc(); + } + else{ + Complex[] ncoef = null; + Complex[] dcoef = null; + switch(this.integMethod){ + // Trapezium rule + case 0: ncoef = Complex.oneDarray(2); + ncoef[0].reset(this.deltaT*this.cConst,0.0D); + ncoef[1].reset(this.deltaT*this.cConst,0.0D); + super.zNumer=new ComplexPoly(1); + super.zNumer.resetPoly(ncoef); + super.zNumerDeg=1; + dcoef = Complex.oneDarray(2); + dcoef[0].reset(this.bConst*this.deltaT - 2*this.aConst,0.0D); + dcoef[1].reset(this.bConst*this.deltaT + 2*this.aConst,0.0D); + super.zDenom=new ComplexPoly(1); + super.zDenom.resetPoly(dcoef); + super.zDenomDeg=1; + super.zZeros = Complex.oneDarray(1); + super.zZeros[0].reset(-1.0D, 0.0D); + super.zPoles = Complex.oneDarray(1); + super.zPoles[0].reset((2.0D*this.aConst-super.deltaT*this.bConst)/(2.0D*this.aConst+super.deltaT*this.bConst), 0.0D); + break; + // Backward rectangulr rule + case 1: ncoef = Complex.oneDarray(2); + ncoef[0].reset(0.0D,0.0D); + ncoef[1].reset(this.cConst*this.deltaT,0.0D); + super.zNumer=new ComplexPoly(1); + super.zNumer.resetPoly(ncoef); + super.zNumerDeg=1; + dcoef = Complex.oneDarray(2); + dcoef[0].reset(this.bConst*this.deltaT + this.aConst,0.0D); + dcoef[1].reset(this.aConst,0.0D); + super.zDenom=new ComplexPoly(1); + super.zDenom.resetPoly(dcoef); + super.zDenomDeg=1; + super.zZeros = Complex.oneDarray(1); + super.zZeros[0].reset(0.0D, 0.0D); + super.zPoles = Complex.oneDarray(1); + super.zPoles[0].reset(this.aConst/(super.deltaT*this.bConst+this.aConst), 0.0D); + break; + // Foreward rectangular rule + case 2: ncoef = Complex.oneDarray(1); + ncoef[0].reset(this.cConst*this.deltaT,0.0D); + super.zNumer=new ComplexPoly(0); + super.zNumer.resetPoly(ncoef); + super.zNumerDeg=0; + dcoef = Complex.oneDarray(2); + dcoef[0].reset(-this.aConst,0.0D); + dcoef[1].reset(this.bConst*this.deltaT - this.aConst,0.0D); + super.zDenom=new ComplexPoly(1); + super.zDenom.resetPoly(dcoef); + super.zDenomDeg=1; + super.zPoles = Complex.oneDarray(1); + super.zPoles[0].reset(this.aConst/(super.deltaT*this.bConst-this.aConst), 0.0D); + break; + default: System.out.println("Integration method option in Transducer must be 0,1 or 2"); + System.out.println("It was set at "+integMethod); + System.out.println("z-transform not performed"); + } + } + } + + // Perform z transform setting delta T + public void zTransform(double deltaT){ + super.deltaT=deltaT; + zTransform(); + } + + // Get the s-domain output for a given s-value and a given input. + public Complex getOutputS(Complex sValue, Complex iinput){ + super.sValue=sValue; + super.inputS=iinput; + return this.getOutputS(); + } + + // Get the s-domain output for the stored input and s-value. + public Complex getOutputS(){ + Complex num = Complex.plusOne(); + num = num.times(this.cConst); + Complex den = new Complex(); + den = this.sValue.times(this.aConst); + den = den.plus(this.bConst); + Complex term = new Complex(); + term = num.over(den); + super.outputS = term.times(super.inputS); + if(super.deadTime!=0.0D)super.outputS = super.outputS.times(Complex.exp(super.sValue.times(-super.deadTime))); + return super.outputS; + } + + // Calculate the current time domain output for a given input and given time + // resets deltaT + public void calcOutputT(double ttime, double inp){ + if(ttime<=time[this.sampLen-1])throw new IllegalArgumentException("Current time equals or is less than previous time"); + super.deltaT = ttime - super.time[this.sampLen-1]; + super.sampFreq = 1.0D/super.deltaT; + super.deadTimeWarning("calcOutputT(time, input)"); + for(int i=0; i<super.sampLen-2; i++){ + super.time[i]=super.time[i+1]; + super.inputT[i]=super.inputT[i+1]; + super.outputT[i]=super.outputT[i+1]; + } + super.time[super.sampLen-1]=ttime; + super.inputT[super.sampLen-1]=inp; + super.outputT[super.sampLen-1]=Double.NaN; + this.calcOutputT(); + } + + // Get the output for the stored sampled input, time and deltaT. + public void calcOutputT(){ + super.deadTimeWarning("calcOutputT()"); + super.outputT[sampLen-1] = (this.bConst*super.inputT[sampLen-1] + this.aConst*(super.inputT[sampLen-1]-super.inputT[sampLen-2])/super.deltaT)/this.cConst; + } + + + // Get the s-domain zeros + public Complex[] getSzeros(){ + System.out.println("This standard first order process (class Transducer) has no s-domain zeros"); + return null; + } + + // Deep copy + public Transducer copy(){ + if(this==null){ + return null; + } + else{ + Transducer bb = new Transducer(); + this.copyBBvariables(bb); + + bb.aConst = this.aConst; + bb.bConst = this.bConst; + bb.cConst = this.cConst; + + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} diff --git a/src/main/java/flanagan/control/ZeroOrderHold.java b/src/main/java/flanagan/control/ZeroOrderHold.java new file mode 100755 index 0000000000000000000000000000000000000000..65a67922071daa3b34114836a23c707b12ae0761 --- /dev/null +++ b/src/main/java/flanagan/control/ZeroOrderHold.java @@ -0,0 +1,137 @@ +/* Class ZeroOrderHold +* +* This class contains the constructor to create an instance of +* a zero order hold (ZOH) and the methods needed to use this ZOH +* in control loops in the time domain, Laplace transform s domain +* or the z-transform z domain. +* +* s-domain transfer function = (1 - exp(-Td.s))/s +* Td is the delay time. +* Pade approximation always used in s-domain +* 1 to 4 order Pade approximations available +* +* This class is a subclass of the superclass BlackBox. +* +* Author: Michael Thomas Flanagan. +* +* Created: 26 June 2003. +* Updated: 2 July 2006, 6 April 2008, 2 December 2008, 6-7 November 2009 +* +* DOCUMENTATION: +* See Michael T Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ZeroOrderHold.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, +* this list of conditions and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission +* from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.control; + +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; + +public class ZeroOrderHold extends BlackBox{ + + // Constructor + public ZeroOrderHold(double deltaT, int orderPade){ + super("ZeroOrderHold"); + super.sPoles = Complex.oneDarray(1); + super.setDeltaT(deltaT); + super.setPadeOrder(orderPade); + this.setNumDen(deltaT); + + } + + // Constructor + // Default Pade approximation order = 2 + public ZeroOrderHold(double deltaT){ + super("ZeroOrderHold"); + super.sPoles = Complex.oneDarray(1); + super.setDeltaT(deltaT); + this.setNumDen(deltaT); + } + + // Constructor + // for copy purposes + private ZeroOrderHold(){ + super("ZeroOrderHold"); + } + + + // set the numerators and denominators + // same polynomials, using Pade approximation for Pade and non-Pade forms + public void setNumDen(double deltaT){ + // set denominator, s + super.sDenom = new ComplexPoly(0.0D, 1.0D); + super.sPoles[0].reset(0.0D, 0.0D); + + // set exp(-sT) part of pade numerator + super.sNumer = new ComplexPoly(1.0D); + super.deadTime = deltaT; + super.pade(); + super.deadTime = 0.0D; + + // add 1 to exp(-sT)[=padeNumer/padeDenom]/s + super.sNumerPade = super.sNumerPade.plus(super.sDenomPade); + super.sZerosPade = sNumerPade.rootsNoMessages(); + + super.sNumer = super.sNumerPade; + super.sDenom = super.sDenomPade; + super.sPoles = super.sPolesPade; + super.sZeros = super.sZerosPade; + + super.sNumerDegPade = super.sNumerPade.getDeg(); + super.sDenomDegPade = super.sDenomPade.getDeg(); + super.sNumerDeg = super.sNumerDegPade; + super.sDenomDeg = super.sDenomDegPade; + + if(super.sNumerDeg==0){ + super.sNumerScaleFactor = super.sNumer.coeffCopy(0); + } + else{ + super.sNumerScaleFactor = BlackBox.scaleFactor(super.sNumerPade, super.sZerosPade); + } + if(super.sDenomDeg==0){ + super.sDenomScaleFactor = super.sDenom.coeffCopy(0); + } + else{ + super.sDenomScaleFactor = BlackBox.scaleFactor(super.sDenomPade, super.sPolesPade); + } + } + + // Deep copy + public ZeroOrderHold copy(){ + if(this==null){ + return null; + } + else{ + ZeroOrderHold bb = new ZeroOrderHold(); + this.copyBBvariables(bb); + + return bb; + } + } + + // Clone - overrides Java.Object method clone + public Object clone(){ + return (Object)this.copy(); + } +} diff --git a/src/main/java/flanagan/integration/DerivFunction.java b/src/main/java/flanagan/integration/DerivFunction.java new file mode 100755 index 0000000000000000000000000000000000000000..a79304146bfa172e03aae945dd5153eccba6dd30 --- /dev/null +++ b/src/main/java/flanagan/integration/DerivFunction.java @@ -0,0 +1,37 @@ +/* +* Interface DerivFunction +* +* This class provides the interface by which a +* single ODE may be coded and supplied to the methods +* in the class RungeKutta +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: February 2002 +* UPDATE: 22 June 2003 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/RungeKutta.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) April 2004 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.integration; + +// Interface for RungeKutta class (single ODE) +public interface DerivFunction{ + double deriv(double x, double y); +} diff --git a/src/main/java/flanagan/integration/DerivnFunction.java b/src/main/java/flanagan/integration/DerivnFunction.java new file mode 100755 index 0000000000000000000000000000000000000000..a394d5bc81a4feab1a3e52ef09cba193cb0d141c --- /dev/null +++ b/src/main/java/flanagan/integration/DerivnFunction.java @@ -0,0 +1,38 @@ +/* +* Interface DerivnFunction +* +* This interface provides the abstract method +* through which a set of ODEs may be coded and +* supplied to the the class RungeKutta +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: February 2002 +* UPDATE: 22 June 2003 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/RungeKutta.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) April 2004 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.integration; + +// Interface for RungeKutta class (n ODEs) +public interface DerivnFunction{ + double[] derivn(double x, double[] y); +} + diff --git a/src/main/java/flanagan/integration/IntegralFunction.java b/src/main/java/flanagan/integration/IntegralFunction.java new file mode 100755 index 0000000000000000000000000000000000000000..4b5a003f63a5608fc4733442e3763a50a4ab576c --- /dev/null +++ b/src/main/java/flanagan/integration/IntegralFunction.java @@ -0,0 +1,37 @@ +/* +* Interface IntegralFunction +* +* This interface provides the abstract method through which +* functions to be integrated by methods in the Class Integration +* may be coded and supplied to the Integration class. +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: February 2002 +* UPDATE: 22 June 2003 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Integration.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) April 2004 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.integration; + +// Interface for Integration class +public interface IntegralFunction{ + double function(double x); +} diff --git a/src/main/java/flanagan/integration/Integration.java b/src/main/java/flanagan/integration/Integration.java new file mode 100755 index 0000000000000000000000000000000000000000..b390099c9a3c0f9bc74fe2ed9908ad2f8e2ad4ca --- /dev/null +++ b/src/main/java/flanagan/integration/Integration.java @@ -0,0 +1,472 @@ +/* +* Class Integration +* interface IntegralFunction also required +* +* Contains the methods for Gaussian-Legendre quadrature, the +* backward and forward rectangular rules and the trapezium rule +* +* The function to be integrated is supplied by means of +* an interface, IntegralFunction +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: February 2002 +* UPDATE: 22 June 2003, 16 July 2006, 25 April 2007, 2 May 2007, 4 July 2008, 22 September 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Integration.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.integration; + +import java.util.*; +import flanagan.math.Fmath; + +// Numerical integration class +public class Integration{ + + private IntegralFunction integralFunc = null; // Function to be integrated + private boolean setFunction = false; // = true when IntegralFunction set + private double lowerLimit = Double.NaN; // Lower integration limit + private double upperLimit = Double.NaN; // Upper integration limit + private boolean setLimits = false; // = true when limits set + + private int glPoints = 0; // Number of points in the Gauss-Legendre integration + private boolean setGLpoints = false; // = true when glPoints set + private int nIntervals = 0; // Number of intervals in the rectangular rule integrations + private boolean setIntervals = false; // = true when nIntervals set + + private double integralSum = 0.0D; // Sum returned by the numerical integration method + private boolean setIntegration = false; // = true when integration performed + + // ArrayLists to hold Gauss-Legendre Coefficients saving repeated calculation + private static ArrayList<Integer> gaussQuadIndex = new ArrayList<Integer>(); // Gauss-Legendre indices + private static ArrayList<double[]> gaussQuadDistArrayList = new ArrayList<double[]>(); // Gauss-Legendre distances + private static ArrayList<double[]> gaussQuadWeightArrayList = new ArrayList<double[]>();// Gauss-Legendre weights + + // Iterative trapezium rule + private double requiredAccuracy = 0.0D; // required accuracy at which iterative trapezium is terminated + private double trapeziumAccuracy = 0.0D; // actual accuracy at which iterative trapezium is terminated as instance variable + private static double trapAccuracy = 0.0D; // actual accuracy at which iterative trapezium is terminated as class variable + private int maxIntervals = 0; // maximum number of intervals allowed in iterative trapezium + private int trapeziumIntervals = 1; // number of intervals in trapezium at which accuracy was satisfied as instance variable + private static int trapIntervals = 1; // number of intervals in trapezium at which accuracy was satisfied as class variable + + // CONSTRUCTORS + + // Default constructor + public Integration(){ + } + + // Constructor taking function to be integrated + public Integration(IntegralFunction intFunc){ + this.integralFunc = intFunc; + this.setFunction = true; + } + + // Constructor taking function to be integrated and the limits + public Integration(IntegralFunction intFunc, double lowerLimit, double upperLimit){ + this.integralFunc = intFunc; + this.setFunction = true; + this.lowerLimit = lowerLimit; + this.upperLimit = upperLimit; + this.setLimits = true; + } + + // SET METHODS + + // Set function to be integrated + public void setIntegrationFunction(IntegralFunction intFunc){ + this.integralFunc = intFunc; + this.setFunction = true; + } + + // Set limits + public void setLimits(double lowerLimit, double upperLimit){ + this.lowerLimit = lowerLimit; + this.upperLimit = upperLimit; + this.setLimits = true; + } + + // Set lower limit + public void setLowerLimit(double lowerLimit){ + this.lowerLimit = lowerLimit; + if(!Fmath.isNaN(this.upperLimit))this.setLimits=true; + } + + // Set lower limit + public void setlowerLimit(double lowerLimit){ + this.lowerLimit = lowerLimit; + if(!Fmath.isNaN(this.upperLimit))this.setLimits=true; + } + + // Set upper limit + public void setUpperLimit(double upperLimit){ + this.upperLimit = upperLimit; + if(!Fmath.isNaN(this.lowerLimit))this.setLimits=true; + } + + // Set upper limit + public void setupperLimit(double upperLimit){ + this.upperLimit = upperLimit; + if(!Fmath.isNaN(this.lowerLimit))this.setLimits=true; + } + + // Set number of points in the Gaussian Legendre integration + public void setGLpoints(int nPoints){ + this.glPoints = nPoints; + this.setGLpoints = true; + } + + // Set number of intervals in trapezoidal, forward or backward rectangular integration + public void setNintervals(int nIntervals){ + this.nIntervals = nIntervals; + this.setIntervals = true; + } + + // GET METHODS + + // Get the sum returned by the numerical integration + public double getIntegralSum(){ + if(!this.setIntegration)throw new IllegalArgumentException("No integration has been performed"); + return this.integralSum; + } + + // GAUSSIAN-LEGENDRE QUADRATURE + + // Numerical integration using n point Gaussian-Legendre quadrature (instance method) + // All parametes preset + public double gaussQuad(){ + if(!this.setGLpoints)throw new IllegalArgumentException("Number of points not set"); + if(!this.setLimits)throw new IllegalArgumentException("One limit or both limits not set"); + if(!this.setFunction)throw new IllegalArgumentException("No integral function has been set"); + + double[] gaussQuadDist = new double[glPoints]; + double[] gaussQuadWeight = new double[glPoints]; + double sum=0.0D; + double xplus = 0.5D*(upperLimit + lowerLimit); + double xminus = 0.5D*(upperLimit - lowerLimit); + double dx = 0.0D; + boolean test = true; + int k=-1, kn=-1; + + // Get Gauss-Legendre coefficients, i.e. the weights and scaled distances + // Check if coefficients have been already calculated on an earlier call + if(!this.gaussQuadIndex.isEmpty()){ + for(k=0; k<this.gaussQuadIndex.size(); k++){ + Integer ki = this.gaussQuadIndex.get(k); + if(ki.intValue()==this.glPoints){ + test=false; + kn = k; + } + } + } + + if(test){ + // Calculate and store coefficients + Integration.gaussQuadCoeff(gaussQuadDist, gaussQuadWeight, glPoints); + Integration.gaussQuadIndex.add(new Integer(glPoints)); + Integration.gaussQuadDistArrayList.add(gaussQuadDist); + Integration.gaussQuadWeightArrayList.add(gaussQuadWeight); + } + else{ + // Recover coefficients + gaussQuadDist = gaussQuadDistArrayList.get(kn); + gaussQuadWeight = gaussQuadWeightArrayList.get(kn); + } + + // Perform summation + for(int i=0; i<glPoints; i++){ + dx = xminus*gaussQuadDist[i]; + sum += gaussQuadWeight[i]*this.integralFunc.function(xplus+dx); + } + this.integralSum = sum*xminus; // rescale + this.setIntegration = true; // integration performed + return this.integralSum; // return value + } + + // Numerical integration using n point Gaussian-Legendre quadrature (instance method) + // All parametes except the number of points in the Gauss-Legendre integration preset + public double gaussQuad(int glPoints){ + this.glPoints = glPoints; + this.setGLpoints = true; + return this.gaussQuad(); + } + + // Numerical integration using n point Gaussian-Legendre quadrature (static method) + // All parametes provided + public static double gaussQuad(IntegralFunction intFunc, double lowerLimit, double upperLimit, int glPoints){ + Integration intgrtn = new Integration(intFunc, lowerLimit, upperLimit); + return intgrtn.gaussQuad(glPoints); + } + + // Returns the distance (gaussQuadDist) and weight coefficients (gaussQuadCoeff) + // for an n point Gauss-Legendre Quadrature. + // The Gauss-Legendre distances, gaussQuadDist, are scaled to -1 to 1 + // See Numerical Recipes for details + public static void gaussQuadCoeff(double[] gaussQuadDist, double[] gaussQuadWeight, int n){ + + double z=0.0D, z1=0.0D; + double pp=0.0D, p1=0.0D, p2=0.0D, p3=0.0D; + + double eps = 3e-11; // set required precision + double x1 = -1.0D; // lower limit + double x2 = 1.0D; // upper limit + + // Calculate roots + // Roots are symmetrical - only half calculated + int m = (n+1)/2; + double xm = 0.5D*(x2+x1); + double xl = 0.5D*(x2-x1); + + // Loop for each root + for(int i=1; i<=m; i++){ + // Approximation of ith root + z = Math.cos(Math.PI*(i-0.25D)/(n+0.5D)); + + // Refinement on above using Newton's method + do{ + p1 = 1.0D; + p2 = 0.0D; + + // Legendre polynomial (p1, evaluated at z, p2 is polynomial of + // one order lower) recurrence relationsip + for(int j=1; j<=n; j++){ + p3 = p2; + p2 = p1; + p1= ((2.0D*j - 1.0D)*z*p2 - (j - 1.0D)*p3)/j; + } + pp = n*(z*p1 - p2)/(z*z - 1.0D); // Derivative of p1 + z1 = z; + z = z1 - p1/pp; // Newton's method + } while(Math.abs(z - z1) > eps); + + gaussQuadDist[i-1] = xm - xl*z; // Scale root to desired interval + gaussQuadDist[n-i] = xm + xl*z; // Symmetric counterpart + gaussQuadWeight[i-1] = 2.0*xl/((1.0 - z*z)*pp*pp); // Compute weight + gaussQuadWeight[n-i] = gaussQuadWeight[i-1]; // Symmetric counterpart + } + } + + // TRAPEZIUM METHODS + + // Numerical integration using the trapeziodal rule (instance method) + // all parameters preset + public double trapezium(){ + if(!this.setIntervals)throw new IllegalArgumentException("Number of intervals not set"); + if(!this.setLimits)throw new IllegalArgumentException("One limit or both limits not set"); + if(!this.setFunction)throw new IllegalArgumentException("No integral function has been set"); + + double y1 = 0.0D; + double interval = (this.upperLimit - this.lowerLimit)/this.nIntervals; + double x0 = this.lowerLimit; + double x1 = this.lowerLimit + interval; + double y0 = this.integralFunc.function(x0); + this.integralSum = 0.0D; + + for(int i=0; i<nIntervals; i++){ + // adjust last interval for rounding errors + if(x1>this.upperLimit){ + x1 = this.upperLimit; + interval -= (x1 - this.upperLimit); + } + + // perform summation + y1 = this.integralFunc.function(x1); + this.integralSum += 0.5D*(y0+y1)*interval; + x0 = x1; + y0 = y1; + x1 += interval; + } + this.setIntegration = true; + return this.integralSum; + } + + // Numerical integration using the trapeziodal rule (instance method) + // all parameters except the number of intervals preset + public double trapezium(int nIntervals){ + this.nIntervals = nIntervals; + this.setIntervals = true; + return this.trapezium(); + } + + // Numerical integration using the trapeziodal rule (static method) + // all parameters to be provided + public static double trapezium(IntegralFunction intFunc, double lowerLimit, double upperLimit, int nIntervals){ + Integration intgrtn = new Integration(intFunc, lowerLimit, upperLimit); + return intgrtn.trapezium(nIntervals); + } + + // Numerical integration using an iteration on the number of intervals in the trapeziodal rule + // until two successive results differ by less than a predetermined accuracy times the penultimate result + public double trapezium(double accuracy, int maxIntervals){ + this.requiredAccuracy = accuracy; + this.maxIntervals = maxIntervals; + this.trapeziumIntervals = 1; + + double summ = this.trapezium(this.integralFunc, this.lowerLimit, this.upperLimit, 1); + double oldSumm = summ; + int i = 2; + for(i=2; i<=this.maxIntervals; i++){ + summ = this.trapezium(this.integralFunc, this.lowerLimit, this.upperLimit, i); + this.trapeziumAccuracy = Math.abs((summ - oldSumm)/oldSumm); + if(this.trapeziumAccuracy<=this.requiredAccuracy)break; + oldSumm = summ; + } + + if(i > this.maxIntervals){ + System.out.println("accuracy criterion was not met in Integration.trapezium - current sum was returned as result."); + this.trapeziumIntervals = this.maxIntervals; + } + else{ + this.trapeziumIntervals = i; + } + Integration.trapIntervals = this.trapeziumIntervals; + Integration.trapAccuracy = this.trapeziumAccuracy; + return summ; + } + + // Numerical integration using an iteration on the number of intervals in the trapeziodal rule (static method) + // until two successive results differ by less than a predtermined accuracy times the penultimate result + // All parameters to be provided + public static double trapezium(IntegralFunction intFunc, double lowerLimit, double upperLimit, double accuracy, int maxIntervals){ + Integration intgrtn = new Integration(intFunc, lowerLimit, upperLimit); + return intgrtn.trapezium(accuracy, maxIntervals); + } + + // Get the number of intervals at which accuracy was last met in trapezium if using the instance trapezium call + public int getTrapeziumIntervals(){ + return this.trapeziumIntervals; + } + + // Get the number of intervals at which accuracy was last met in trapezium if using static trapezium call + public static int getTrapIntervals(){ + return Integration.trapIntervals; + } + + // Get the actual accuracy acheived when the iterative trapezium calls were terminated, using the instance method + public double getTrapeziumAccuracy(){ + return this.trapeziumAccuracy; + } + + // Get the actual accuracy acheived when the iterative trapezium calls were terminated, using the static method + public static double getTrapAccuracy(){ + return Integration.trapAccuracy; + } + + // BACKWARD RECTANGULAR METHODS + + // Numerical integration using the backward rectangular rule (instance method) + // All parameters preset + public double backward(){ + if(!this.setIntervals)throw new IllegalArgumentException("Number of intervals not set"); + if(!this.setLimits)throw new IllegalArgumentException("One limit or both limits not set"); + if(!this.setFunction)throw new IllegalArgumentException("No integral function has been set"); + + double interval = (this.upperLimit - this.lowerLimit)/this.nIntervals; + double x = this.lowerLimit + interval; + double y = this.integralFunc.function(x); + this.integralSum = 0.0D; + + for(int i=0; i<this.nIntervals; i++){ + // adjust last interval for rounding errors + if(x>this.upperLimit){ + x = this.upperLimit; + interval -= (x - this.upperLimit); + } + + // perform summation + y = this.integralFunc.function(x); + this.integralSum += y*interval; + x += interval; + } + + this.setIntegration = true; + return this.integralSum; + } + + // Numerical integration using the backward rectangular rule (instance method) + // all parameters except number of intervals preset + public double backward(int nIntervals){ + this.nIntervals = nIntervals; + this.setIntervals = true; + return this.backward(); + } + + // Numerical integration using the backward rectangular rule (static method) + // all parameters must be provided + public static double backward(IntegralFunction intFunc, double lowerLimit, double upperLimit, int nIntervals){ + Integration intgrtn = new Integration(intFunc, lowerLimit, upperLimit); + return intgrtn.backward(nIntervals); + } + + // FORWARD RECTANGULAR METHODS + + // Numerical integration using the forward rectangular rule + // all parameters preset + public double forward(){ + + double interval = (this.upperLimit - this.lowerLimit)/this.nIntervals; + double x = this.lowerLimit; + double y = this.integralFunc.function(x); + this.integralSum = 0.0D; + + for(int i=0; i<this.nIntervals; i++){ + // adjust last interval for rounding errors + if(x>this.upperLimit){ + x = this.upperLimit; + interval -= (x - this.upperLimit); + } + + // perform summation + y = this.integralFunc.function(x); + this.integralSum += y*interval; + x += interval; + } + this.setIntegration = true; + return this.integralSum; + } + + // Numerical integration using the forward rectangular rule + // all parameters except number of intervals preset + public double forward(int nIntervals){ + this.nIntervals = nIntervals; + this.setIntervals = true; + return this.forward(); + } + + // Numerical integration using the forward rectangular rule (static method) + // all parameters provided + public static double forward(IntegralFunction integralFunc, double lowerLimit, double upperLimit, int nIntervals){ + Integration intgrtn = new Integration(integralFunc, lowerLimit, upperLimit); + return intgrtn.forward(nIntervals); + } + + public static double foreward(IntegralFunction integralFunc, double lowerLimit, double upperLimit, int nIntervals){ + Integration intgrtn = new Integration(integralFunc, lowerLimit, upperLimit); + return intgrtn.forward(nIntervals); + } + + +} diff --git a/src/main/java/flanagan/integration/RungeKutta.java b/src/main/java/flanagan/integration/RungeKutta.java new file mode 100755 index 0000000000000000000000000000000000000000..f9fe808da6caeeeb34ff435530b9597dcd71ebe8 --- /dev/null +++ b/src/main/java/flanagan/integration/RungeKutta.java @@ -0,0 +1,416 @@ +/* +* Class RungeKutta +* requires interfaces DerivFunction and DerivnFunction +* +* Contains the methods for the Runge-Kutta procedures for solving +* single or solving sets of ordinary differential equations (ODEs) +* [draws heavily on the approach adopted in Numerical Recipes +* (C language version)http://www.nr.com] +* +* A single ODE is supplied by means of an interface, +* DerivFunction +* A set of ODEs is supplied by means of an interface, +* DerivnFunction +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: February 2002 +* UPDATES: 22 June 2003, April 2004, +* 15 September 2006 (to incorporate improvements suggested by Klaus Benary [Klaus.Benary@gede.de]) +* 11 April 2007, 25 April 2007, 4 July 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/RungeKutta.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) April 2004, September 2006, April 2007 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.integration; + + +// Class for Runge-Kutta solution of ordinary differential equations +public class RungeKutta{ + + public RungeKutta(){ + } + + private static double SAFETY=0.9D; // safety scaling factor for Runge Kutta Fehlberg tolerance check + + // Fourth order Runge-Kutta for a single ordinary differential equation + public static double fourthOrder(DerivFunction g, double x0, double y0, double xn, double h){ + double k1 = 0.0D, k2 = 0.0D, k3 = 0.0D, k4 = 0.0D; + double x = 0.0D, y = y0; + + // Calculate nsteps + double ns = (xn - x0)/h; + ns = Math.rint(ns); + int nsteps = (int) ns; // number of steps + h = (xn - x0)/ns; + + for(int i=0; i<nsteps; i++){ + x = x0 + i*h; + + k1 = h*g.deriv(x, y); + k2 = h*g.deriv(x + h/2, y + k1/2); + k3 = h*g.deriv(x + h/2, y + k2/2); + k4 = h*g.deriv(x + h, y + k3); + + y += k1/6 + k2/3 + k3/3 + k4/6; + } + return y; + } + + // Fourth order Runge-Kutta for n (nequ) ordinary differential equations (ODE) + public static double[] fourthOrder(DerivnFunction g, double x0, double[] y0, double xn, double h){ + int nequ = y0.length; + double[] k1 =new double[nequ]; + double[] k2 =new double[nequ]; + double[] k3 =new double[nequ]; + double[] k4 =new double[nequ]; + double[] y =new double[nequ]; + double[] yd =new double[nequ]; + double[] dydx =new double[nequ]; + double x = 0.0D; + + // Calculate nsteps + double ns = (xn - x0)/h; + ns = Math.rint(ns); + int nsteps = (int) ns; + h = (xn - x0)/ns; + + // initialise + for(int i=0; i<nequ; i++)y[i] = y0[i]; + + // iteration over allowed steps + for(int j=0; j<nsteps; j++){ + x = x0 + j*h; + dydx = g.derivn(x, y); + for(int i=0; i<nequ; i++)k1[i] = h*dydx[i]; + + for(int i=0; i<nequ; i++)yd[i] = y[i] + k1[i]/2; + dydx = g.derivn(x + h/2, yd); + for(int i=0; i<nequ; i++)k2[i] = h*dydx[i]; + + for(int i=0; i<nequ; i++)yd[i] = y[i] + k2[i]/2; + dydx = g.derivn(x + h/2, yd); + for(int i=0; i<nequ; i++)k3[i] = h*dydx[i]; + + for(int i=0; i<nequ; i++)yd[i] = y[i] + k3[i]; + dydx = g.derivn(x + h, yd); + for(int i=0; i<nequ; i++)k4[i] = h*dydx[i]; + + for(int i=0; i<nequ; i++)y[i] += k1[i]/6 + k2[i]/3 + k3[i]/3 + k4[i]/6; + + } + return y; + } + + // Runge-Kutta-Cash-Karp for a single ordinary differential equation (ODE) + public static double cashKarp(DerivFunction g, double x0, double y0, double xn, double h, double abstol, double reltol, int maxiter){ + double k1 = 0.0D, k2 = 0.0D, k3 = 0.0D, k4 = 0.0D, k5 = 0.0D, k6 = 0.0D; + double y = y0, y6 = 0.0D, y5 = 0.0D, yd = 0.0D, dydx = 0.0D; + double x = x0, err = 0.0D, delta = 0.0D, tol = 0.0D; + int i = 0; + + while(x<xn){ + i++; + if(i>maxiter)throw new ArithmeticException("Maximum number of iterations exceeded"); + dydx = g.deriv(x, y); + k1 = h*dydx; + + yd = y + k1/5.0; + dydx = g.deriv(x + h/5.0, yd); + k2 = h*dydx; + + yd = y + (3.0*k1 + 9.0*k2)/40.0; + dydx = g.deriv(x + 3.0*h/10.0, yd); + k3 = h*dydx; + + yd = y + (3.0*k1 - 9.0*k2 + 12.0*k3)/10.0; + dydx = g.deriv(x + 3.0*h/5.0, yd); + k4 = h*dydx; + + yd = y -11.0*k1/54.0 + 5.0*k2/2.0 - 70.0*k3/27.0 + 35.0*k4/27.0; + dydx = g.deriv(x + h, yd); + k5 = h*dydx; + + yd = y + 1631.0*k1/55296.0 + 175.0*k2/512.0 + 575.0*k3/13824.0 + 44275.0*k4/110592.0 + 253.0*k5/4096.0; + dydx = g.deriv(x + 7.0*h/8.0, yd); + k6 = h*dydx; + + y5 = y + 2825.0*k1/27648.0 + 18575.0*k3/48384.0 + 13525.0*k4/55296.0 + 277.0*k5/14336.0 + k6/4.0; + y6 = y + 37*k1/378.0 + 250.0*k3/621.0 + 125.0*k4/594.0 + 512.0*k6/1771.0; + err = Math.abs(y6 - y5); + tol= err/(Math.abs(y5)*reltol + abstol); + if(tol<=1.0){ + x += h; + delta = SAFETY*Math.pow(tol, -0.2); + if(delta>4.0){ + h*= 4.0; + }else if(delta >1.0){ + h*=delta; + } + if(x+h > xn)h = xn-x; + y = y5; + } + else{ + delta = SAFETY*Math.pow(tol,-0.25); + if(delta < 0.1) h *= 0.1; + else h *= delta; + } + } + return y; + } + + // maximum iteration default option + public static double cashKarp(DerivFunction g, double x0, double y0, double xn, double h, double abstol, double reltol){ + + double nsteps = (xn - x0)/h; + int maxiter = (int) nsteps*100; + + return cashKarp(g, x0, y0, xn, h, abstol, reltol, maxiter); + } + + + // Runge-Kutta-Cash-Karp for n (nequ) ordinary differential equations (ODEs + public static double[] cashKarp(DerivnFunction g, double x0, double[] y0, double xn, double h, double abstol, double reltol, int maxiter){ + int nequ = y0.length; + double[] k1 =new double[nequ]; + double[] k2 =new double[nequ]; + double[] k3 =new double[nequ]; + double[] k4 =new double[nequ]; + double[] k5 =new double[nequ]; + double[] k6 =new double[nequ]; + double[] y =new double[nequ]; + double[] y6 =new double[nequ]; + double[] y5 =new double[nequ]; + double[] yd =new double[nequ]; + double[] dydx =new double[nequ]; + + double x = 0.0D, err = 0.0D, maxerr = 0.0D, delta = 0.0D, tol = 1.0D; + int ii = 0; + + // initialise + for(int i=0; i<nequ; i++)y[i] = y0[i]; + x = x0; + + while(x<xn){ + ii++; + if(ii>maxiter)throw new ArithmeticException("Maximum number of iterations exceeded"); + + dydx = g.derivn(x, y); + for(int i=0; i<nequ; i++)k1[i] = h*dydx[i]; + + for(int i=0; i<nequ; i++)yd[i] = y[i] + k1[i]/5.0; + dydx = g.derivn(x + h/5.0, yd); + for(int i=0; i<nequ; i++)k2[i] = h*dydx[i]; + + for(int i=0; i<nequ; i++)yd[i] = y[i] + (3.0*k1[i] + 9.0*k2[i])/40.0; + dydx = g.derivn(x + 3.0*h/10.0, yd); + for(int i=0; i<nequ; i++)k3[i] = h*dydx[i]; + + for(int i=0; i<nequ; i++)yd[i] = y[i] + (3.0*k1[i] - 9.0*k2[i] + 12.0*k3[i])/10.0; + dydx = g.derivn(x + 3.0*h/5.0, yd); + for(int i=0; i<nequ; i++)k4[i] = h*dydx[i]; + + for(int i=0; i<nequ; i++)yd[i] = y[i] -11.0*k1[i]/54.0 + 5.0*k2[i]/2.0 - 70.0*k3[i]/27.0 + 35.0*k4[i]/27.0; + dydx = g.derivn(x + h, yd); + for(int i=0; i<nequ; i++)k5[i] = h*dydx[i]; + + for(int i=0; i<nequ; i++)yd[i] = y[i] + 1631.0*k1[i]/55296.0 + 175.0*k2[i]/512.0 + 575.0*k3[i]/13824.0 + 44275.0*k4[i]/110592.0 + 253.0*k5[i]/4096.0; + dydx = g.derivn(x + 7.0*h/8.0, yd); + for(int i=0; i<nequ; i++)k6[i] = h*dydx[i]; + + maxerr=0.0D; + for(int i=0; i<nequ; i++){ + y5[i] = y[i] + 2825.0*k1[i]/27648.0 + 18575.0*k3[i]/48384.0 + 13525.0*k4[i]/55296.0 + 277.0*k5[i]/14336.0 + k6[i]/4.0; + y6[i] = y[i] + 37*k1[i]/378.0 + 250.0*k3[i]/621.0 + 125.0*k4[i]/594.0 + 512.0*k6[i]/1771.0; + err = Math.abs(y6[i] - y5[i]); + tol= Math.abs(y5[i])*reltol + abstol; + maxerr = Math.max(maxerr,err/tol); + } + if(maxerr<=1.0D){ + x += h; + delta = SAFETY*Math.pow(maxerr, -0.2); + if(delta>4.0){ + h*= 4.0; + } + else if (delta > 1.0){ + h*=delta; + } + if(x+h > xn)h = xn-x; + y = (double[])y5.clone(); + } + else{ + delta = SAFETY*Math.pow(maxerr,-0.25); + if(delta < 0.1D) h *= 0.1; + else h *= delta; + } + } + return y; + } + + public static double[] cashKarp(DerivnFunction g, double x0, double[] y0, double xn, double h, double abstol, double reltol){ + + double nsteps = (xn - x0)/h; + int maxiter = (int) nsteps*100; + + return cashKarp(g, x0, y0, xn, h, abstol, reltol, maxiter); + } + + // Runge-Kutta-Fehlberg for a single ordinary differential equation (ODE) + public static double fehlberg(DerivFunction g, double x0, double y0, double xn, double h, double abstol, double reltol, int maxiter){ + double k1 = 0.0D, k2 = 0.0D, k3 = 0.0D, k4 = 0.0D, k5 = 0.0D, k6 = 0.0D; + double x = x0, y = y0, y5 = 0.0D, y6 = 0.0D, err = 0.0D, delta = 0.0D, tol = 0.0D; + int i = 0; + + while(x<xn){ + i++; + if(i>maxiter)throw new ArithmeticException("Maximum number of iterations exceeded"); + k1 = h*g.deriv(x, y); + k2 = h*g.deriv(x + h/4.0, y + k1/4.0); + k3 = h*g.deriv(x + 3.0*h/8.0, y + (3.0*k1 + 9.0*k2)/32.0); + k4 = h*g.deriv(x + 12.0*h/13.0, y + (1932.0*k1 - 7200.0*k2 + 7296.0*k3)/2197.0); + k5 = h*g.deriv(x + h, y + 439.0*k1/216.0 - 8.0*k2 + 3680.0*k3/513.0 - 845*k4/4104.0); + k6 = h*g.deriv(x + 0.5*h, y - 8.0*k1/27.0 + 2.0*k2 - 3544.0*k3/2565.0 + 1859.0*k4/4104.0 - 11.0*k5/40.0); + + y5 = y + 25.0*k1/216.0 + 1408.0*k3/2565.0 + 2197.0*k4/4104.0 - k5/5.0; + y6 = y + 16.0*k1/135.0 + 6656.0*k3/12825.0 + 28561.0*k4/56430.0 - 9.0*k5/50.0 + 2.0*k6/55.0; + err = Math.abs(y6 - y5); + tol= err/(Math.abs(y5)*reltol + abstol); + if(tol<=1.0){ + x += h; + delta = SAFETY*Math.pow(tol, -0.2); + if(delta>4.0){ + h*= 4.0; + }else if(delta <1.0){ + h*=delta; + } + if(x+h > xn)h = xn-x; + y = y5; + } + else{ + delta = SAFETY*Math.pow(tol,-0.25); + if(delta < 0.1) h *= 0.1; + else h *= delta; + } + } + return y; + } + + // maximum iteration default option + public static double fehlberg(DerivFunction g, double x0, double y0, double xn, double h, double abstol, double reltol){ + + double nsteps = (xn - x0)/h; + int maxiter = (int) nsteps*100; + + return fehlberg(g, x0, y0, xn, h, abstol, reltol, maxiter); + } + + // Runge-Kutta-Fehlberg for n (nequ) ordinary differential equations (ODEs) + public static double[] fehlberg(DerivnFunction g, double x0, double[] y0, double xn, double h, double abstol, double reltol, int maxiter){ + int nequ = y0.length; + double[] k1 =new double[nequ]; + double[] k2 =new double[nequ]; + double[] k3 =new double[nequ]; + double[] k4 =new double[nequ]; + double[] k5 =new double[nequ]; + double[] k6 =new double[nequ]; + double[] y =new double[nequ]; + double[] y6 =new double[nequ]; + double[] y5 =new double[nequ]; + double[] yd =new double[nequ]; + double[] dydx =new double[nequ]; + + double x = x0, err = 0.0D, maxerr = 0.0D, delta = 0.0D, tol = 1.0D; + int ii = 0; + + // initialise + for(int i=0; i<nequ; i++)y[i] = y0[i]; + + while(x<xn){ + ii++; + if(ii>maxiter)throw new ArithmeticException("Maximum number of iterations exceeded"); + dydx = g.derivn(x, y); + for(int i=0; i<nequ; i++)k1[i] = h*dydx[i]; + + for(int i=0; i<nequ; i++)yd[i] = y[i] + k1[i]/4.0; + dydx = g.derivn(x + h/4.0, yd); + for(int i=0; i<nequ; i++)k2[i] = h*dydx[i]; + + for(int i=0; i<nequ; i++)yd[i] = y[i] + (3.0*k1[i] + 9.0*k2[i])/32.0; + dydx = g.derivn(x + 3.0*h/8.0, yd); + for(int i=0; i<nequ; i++)k3[i] = h*dydx[i]; + + for(int i=0; i<nequ; i++)yd[i] = y[i] + (1932.0*k1[i] - 7200.0*k2[i] + 7296.0*k3[i])/2197.0; + dydx = g.derivn(x + 12.0*h/13.0, yd); + for(int i=0; i<nequ; i++)k4[i] = h*dydx[i]; + + for(int i=0; i<nequ; i++)yd[i] = y[i] + 439.0*k1[i]/216.0 - 8.0*k2[i] + 3680.0*k3[i]/513.0 - 845*k4[i]/4104.0; + dydx = g.derivn(x + h, yd); + for(int i=0; i<nequ; i++)k5[i] = h*dydx[i]; + + for(int i=0; i<nequ; i++)yd[i] = y[i] - 8.0*k1[i]/27.0 + 2.0*k2[i] - 3544.0*k3[i]/2565.0 + 1859.0*k4[i]/4104.0 - 11.0*k5[i]/40.0; + dydx = g.derivn(x + 0.5*h, yd); + for(int i=0; i<nequ; i++)k6[i] = h*dydx[i]; + + maxerr=0.0D; + for(int i=0; i<nequ; i++){ + y5[i] = y[i] + 25.0*k1[i]/216.0 + 1408.0*k3[i]/2565.0 + 2197.0*k4[i]/4104.0 - k5[i]/5.0; + y6[i] = y[i] + 16.0*k1[i]/135.0 + 6656.0*k3[i]/12825.0 + 28561.0*k4[i]/56430.0 - 9.0*k5[i]/50.0 + 2.0*k6[i]/55.0; + err = Math.abs(y6[i] - y5[i]); + tol= y5[i]*reltol + abstol; + maxerr = Math.max(maxerr,err/tol); + } + + if(maxerr<=1.0D){ + x += h; + delta = SAFETY*Math.pow(maxerr, -0.2); + if(delta>4.0){ + h*= 4.0; + } + else if(delta > 1.0){ + h*=delta; + } + if(x+h > xn)h = xn-x; + y = (double[])y5.clone(); + } + else{ + delta = SAFETY*Math.pow(maxerr,-0.25); + if(delta < 0.1) h *= 0.1; + else h *= delta; + } + } + return y; + } + + // maximum iteration default option + public static double[] fehlberg(DerivnFunction g, double x0, double[] y0, double xn, double h, double abstol, double reltol){ + + double nsteps = (xn - x0)/h; + int maxiter = (int) nsteps*100; + + return fehlberg(g, x0, y0, xn, h, abstol, reltol, maxiter); + } +} + + + + + + + + diff --git a/src/main/java/flanagan/interpolation/BiCubicSpline.java b/src/main/java/flanagan/interpolation/BiCubicSpline.java new file mode 100755 index 0000000000000000000000000000000000000000..cfa4aeb311ea69ac20659d335900b779198ef25e --- /dev/null +++ b/src/main/java/flanagan/interpolation/BiCubicSpline.java @@ -0,0 +1,256 @@ +/********************************************************** +* +* BiCubicSpline.java +* +* Class for performing an interpolation on the tabulated +* function y = f(x1,x2) using a natural bicubic spline +* Assumes second derivatives at end points = 0 (natural spine) +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: May 2002 +* UPDATE: 20 May 2003, 17 February 2006, 27 July 2007, 4 December 2007, 21 September 2008, 31 October 2009 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/BiCubicSpline.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.interpolation; + +import flanagan.math.Fmath; + +public class BiCubicSpline{ + + private int nPoints = 0; // no. of x1 tabulated points + private int mPoints = 0; // no. of x2 tabulated points + private double[][] y = null; // y=f(x1,x2) tabulated function + private double[] x1 = null; // x1 in tabulated function f(x1,x2) + private double[] x2 = null; // x2 in tabulated function f(x1,x2) + private double[] xMin = new double[2]; // minimum values of x1 and x2 + private double[] xMax = new double[2]; // maximum values of x1 and x2 + private double[][] d2ydx2inner = null; // second derivatives of first called array of cubic splines + private CubicSpline csn[] = null; // nPoints array of CubicSpline instances + private CubicSpline csm = null; // CubicSpline instance + private boolean derivCalculated = false; // = true when the first called cubic spline derivatives have been calculated + private boolean averageIdenticalAbscissae = false; // if true: the the ordinate values for identical abscissae are averaged + // If false: the abscissae values are separated by 0.001 of the total abscissae range; + private static double potentialRoundingError = 5e-15; // potential rounding error used in checking wheter a value lies within the interpolation bounds (static value) + private static boolean roundingCheck = true; // = true: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit (static value) + + + // Constructor + // Constructor with data arrays initialised to arrays x and y + public BiCubicSpline(double[] x1, double[] x2, double[][] y){ + this.nPoints=x1.length; + this.mPoints=x2.length; + if(this.nPoints!=y.length)throw new IllegalArgumentException("Arrays x1 and y-row are of different length " + this.nPoints + " " + y.length); + if(this.mPoints!=y[0].length)throw new IllegalArgumentException("Arrays x2 and y-column are of different length "+ this.mPoints + " " + y[0].length); + if(this.nPoints<3 || this.mPoints<3)throw new IllegalArgumentException("The data matrix must have a minimum size of 3 X 3"); + + this.csm = new CubicSpline(this.nPoints); + this.csn = CubicSpline.oneDarray(this.nPoints, this.mPoints); + this.x1 = new double[this.nPoints]; + this.x2 = new double[this.mPoints]; + this.y = new double[this.nPoints][this.mPoints]; + this.d2ydx2inner = new double[this.nPoints][this.mPoints]; + for(int i=0; i<this.nPoints; i++){ + this.x1[i]=x1[i]; + } + this.xMin[0] = Fmath.minimum(this.x1); + this.xMax[0] = Fmath.maximum(this.x1); + for(int j=0; j<this.mPoints; j++){ + this.x2[j]=x2[j]; + } + this.xMin[1] = Fmath.minimum(this.x2); + this.xMax[1] = Fmath.maximum(this.x2); + for(int i =0; i<this.nPoints; i++){ + for(int j=0; j<this.mPoints; j++){ + this.y[i][j]=y[i][j]; + } + } + + double[] yTempn = new double[mPoints]; + + for(int i=0; i<this.nPoints; i++){ + for(int j=0; j<mPoints; j++)yTempn[j]=y[i][j]; + this.csn[i].resetData(x2,yTempn); + this.csn[i].calcDeriv(); + this.d2ydx2inner[i]=this.csn[i].getDeriv(); + } + this.derivCalculated = true; + } + + // Constructor with data arrays initialised to zero + // Primarily for use by TriCubicSpline + public BiCubicSpline(int nP, int mP){ + this.nPoints=nP; + this.mPoints=mP; + if(this.nPoints<3 || this.mPoints<3)throw new IllegalArgumentException("The data matrix must have a minimum size of 3 X 3"); + + this.csm = new CubicSpline(this.nPoints); + if(!this.roundingCheck)this.csm.noRoundingErrorCheck(); + + this.csn = CubicSpline.oneDarray(this.nPoints, this.mPoints); + this.x1 = new double[this.nPoints]; + this.x2 = new double[this.mPoints]; + this.y = new double[this.nPoints][this.mPoints]; + this.d2ydx2inner = new double[this.nPoints][this.mPoints]; + } + + // METHODS + + // Reset rounding error check option + // Default option: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit + // This method causes this check to be ignored and an exception to be thrown if any point lies outside the interpolation bounds + public static void noRoundingErrorCheck(){ + BiCubicSpline.roundingCheck = false; + CubicSpline.noRoundingErrorCheck(); + } + + // Reset potential rounding error value + // Default option: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit + // The default value for the potential rounding error is 5e-15*times the 10^exponent of the value outside the bounds + // This method allows the 5e-15 to be reset + public static void potentialRoundingError(double potentialRoundingError){ + BiCubicSpline.potentialRoundingError = potentialRoundingError; + CubicSpline.potentialRoundingError(potentialRoundingError); + } + + // Reset the default handing of identical abscissae with different ordinates + // from the default option of separating the two relevant abscissae by 0.001 of the range + // to avraging the relevant ordinates + public void averageIdenticalAbscissae(){ + this.averageIdenticalAbscissae = true; + for(int i=0; i<this.csn.length; i++)this.csn[i].averageIdenticalAbscissae(); + this.csm.averageIdenticalAbscissae(); + } + + // Resets the x1, x2, y data arrays + // Primarily for use in TiCubicSpline + public void resetData(double[] x1, double[] x2, double[][] y){ + if(x1.length!=y.length)throw new IllegalArgumentException("Arrays x1 and y row are of different length"); + if(x2.length!=y[0].length)throw new IllegalArgumentException("Arrays x2 and y column are of different length"); + if(this.nPoints!=x1.length)throw new IllegalArgumentException("Original array length not matched by new array length"); + if(this.mPoints!=x2.length)throw new IllegalArgumentException("Original array length not matched by new array length"); + + for(int i=0; i<this.nPoints; i++){ + this.x1[i]=x1[i]; + } + + for(int i=0; i<this.mPoints; i++){ + this.x2[i]=x2[i]; + } + + for(int i=0; i<this.nPoints; i++){ + for(int j=0; j<this.mPoints; j++){ + this.y[i][j]=y[i][j]; + } + } + + this.csm = new CubicSpline(this.nPoints); + this.csn = CubicSpline.oneDarray(this.nPoints, this.mPoints); + double[] yTempn = new double[mPoints]; + + for(int i=0; i<this.nPoints; i++){ + for(int j=0; j<mPoints; j++)yTempn[j]=y[i][j]; + this.csn[i].resetData(x2,yTempn); + this.csn[i].calcDeriv(); + this.d2ydx2inner[i]=this.csn[i].getDeriv(); + } + this.derivCalculated = true; + + } + + // Returns a new BiCubicSpline setting internal array size to nP x mP and all array values to zero with natural spline default + // Primarily for use in this.oneDarray for TiCubicSpline + public static BiCubicSpline zero(int nP, int mP){ + if(nP<3 || mP<3)throw new IllegalArgumentException("A minimum of three x three data points is needed"); + BiCubicSpline aa = new BiCubicSpline(nP, mP); + return aa; + } + + // Create a one dimensional array of BiCubicSpline objects of length nP each of internal array size mP x lP + // Primarily for use in TriCubicSpline + public static BiCubicSpline[] oneDarray(int nP, int mP, int lP){ + if(mP<3 || lP<3)throw new IllegalArgumentException("A minimum of three x three data points is needed"); + BiCubicSpline[] a =new BiCubicSpline[nP]; + for(int i=0; i<nP; i++){ + a[i]=BiCubicSpline.zero(mP, lP); + } + return a; + } + + + // Get inner matrix of derivatives + // Primarily used by TriCubicSpline + public double[][] getDeriv(){ + return this.d2ydx2inner; + } + + // Get minimum limits + public double[] getXmin(){ + return this.xMin; + } + + // Get maximum limits + public double[] getXmax(){ + return this.xMax; + } + + // Get limits to x + public double[] getLimits(){ + double[] limits = {xMin[0], xMax[0], xMin[1], xMax[1]}; + return limits; + } + + // Display limits to x + public void displayLimits(){ + System.out.println(" "); + for(int i=0; i<2; i++){ + System.out.println("The limits to the x array " + i + " are " + xMin[i] + " and " + xMax[i]); + } + System.out.println(" "); + } + + // Set inner matrix of derivatives + // Primarily used by TriCubicSpline + public void setDeriv(double[][] d2ydx2){ + this.d2ydx2inner = d2ydx2; + this.derivCalculated = true; + } + + // Returns an interpolated value of y for a value of x + // from a tabulated function y=f(x1,x2) + public double interpolate(double xx1, double xx2){ + + double[] yTempm = new double[this.nPoints]; + + for (int i=0;i<this.nPoints;i++){ + yTempm[i]=this.csn[i].interpolate(xx2); + } + this.csm.resetData(x1,yTempm); + return this.csm.interpolate(xx1); + } +} + diff --git a/src/main/java/flanagan/interpolation/CubicSpline.java b/src/main/java/flanagan/interpolation/CubicSpline.java new file mode 100755 index 0000000000000000000000000000000000000000..4a37cd97c65c83c477f9916c445ba5560e5307bb --- /dev/null +++ b/src/main/java/flanagan/interpolation/CubicSpline.java @@ -0,0 +1,534 @@ +/********************************************************** +* +* Class CubicSpline +* +* Class for performing an interpolation using a cubic spline +* setTabulatedArrays and interpolate adapted, with modification to +* an object-oriented approach, from Numerical Recipes in C (http://www.nr.com/) +* +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: May 2002 +* UPDATE: 29 April 2005, 17 February 2006, 21 September 2006, 4 December 2007 +* 24 March 2008 (Thanks to Peter Neuhaus, Florida Institute for Human and Machine Cognition) +* 21 September 2008 +* 14 January 2009 - point deletion and check for 3 points reordered (Thanks to Jan Sacha, Vrije Universiteit Amsterdam) +* 31 October 2009 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/CubicSpline.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, +* this list of conditions and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission +* from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + + +package flanagan.interpolation; + +import flanagan.math.Fmath; + +public class CubicSpline{ + + private int nPoints = 0; // no. of tabulated points + private int nPointsOriginal = 0; // no. of tabulated points after any deletions of identical points + private double[] y = null; // y=f(x) tabulated function + private double[] x = null; // x in tabulated function f(x) + private int[]newAndOldIndices; // record of indices on ordering x into ascending order + private double xMin = Double.NaN; // minimum x value + private double xMax = Double.NaN; // maximum x value + private double range = Double.NaN; // xMax - xMin + private double[] d2ydx2 = null; // second derivatives of y + private double yp1 = Double.NaN; // first derivative at point one + // default value = NaN (natural spline) + private double ypn = Double.NaN; // first derivative at point n + // default value = NaN (natural spline) + private boolean derivCalculated = false; // = true when the derivatives have been calculated + + private boolean checkPoints = false; // = true when points checked for identical values + private boolean averageIdenticalAbscissae = false; // if true: the the ordinate values for identical abscissae are averaged + // if false: the abscissae values are separated by 0.001 of the total abscissae range; + private static double potentialRoundingError = 5e-15; // potential rounding error used in checking wheter a value lies within the interpolation bounds + private static boolean roundingCheck = true; // = true: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit + + + // Constructors + // Constructor with data arrays initialised to arrays x and y + public CubicSpline(double[] x, double[] y){ + this.nPoints=x.length; + this.nPointsOriginal = this.nPoints; + if(this.nPoints!=y.length)throw new IllegalArgumentException("Arrays x and y are of different length "+ this.nPoints + " " + y.length); + if(this.nPoints<3)throw new IllegalArgumentException("A minimum of three data points is needed"); + this.x = new double[nPoints]; + this.y = new double[nPoints]; + this.d2ydx2 = new double[nPoints]; + for(int i=0; i<this.nPoints; i++){ + this.x[i]=x[i]; + this.y[i]=y[i]; + } + this.orderPoints(); + } + + // Constructor with data arrays initialised to zero + // Primarily for use by BiCubicSpline + public CubicSpline(int nPoints){ + this.nPoints=nPoints; + this.nPointsOriginal = this.nPoints; + if(this.nPoints<3)throw new IllegalArgumentException("A minimum of three data points is needed"); + this.x = new double[nPoints]; + this.y = new double[nPoints]; + this.d2ydx2 = new double[nPoints]; + } + + // METHODS + // Reset rounding error check option + // Default option: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit + // This method causes this check to be ignored and an exception to be thrown if any poit lies outside the interpolation bounds + public static void noRoundingErrorCheck(){ + CubicSpline.roundingCheck = false; + } + + // Reset potential rounding error value + // Default option: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit + // The default value for the potential rounding error is 5e-15*times the 10^exponent of the value outside the bounds + // This method allows the 5e-15 to be reset + public static void potentialRoundingError(double potentialRoundingError){ + CubicSpline.potentialRoundingError = potentialRoundingError; + } + + // Resets the x y data arrays - primarily for use in BiCubicSpline + public void resetData(double[] x, double[] y){ + this.nPoints = this.nPointsOriginal; + if(x.length!=y.length)throw new IllegalArgumentException("Arrays x and y are of different length"); + if(this.nPoints!=x.length)throw new IllegalArgumentException("Original array length not matched by new array length"); + + for(int i=0; i<this.nPoints; i++){ + this.x[i]=x[i]; + this.y[i]=y[i]; + } + this.orderPoints(); + } + + // Reset the default handing of identical abscissae with different ordinates + // from the default option of separating the two relevant abscissae by 0.001 of the range + // to avraging the relevant ordinates + public void averageIdenticalAbscissae(){ + this.averageIdenticalAbscissae = true; + } + + // Sort points into an ascending abscissa order + public void orderPoints(){ + double[] dummy = new double[nPoints]; + this.newAndOldIndices = new int[nPoints]; + // Sort x into ascending order storing indices changes + Fmath.selectionSort(this.x, dummy, this.newAndOldIndices); + // Sort x into ascending order and make y match the new order storing both new x and new y + Fmath.selectionSort(this.x, this.y, this.x, this.y); + + // Minimum and maximum values and range + this.xMin = Fmath.minimum(this.x); + this.xMax = Fmath.maximum(this.x); + range = xMax - xMin; + } + + // get the maximum value + public double getXmax(){ + return this.xMax; + } + + // get the minimum value + public double getXmin(){ + return this.xMin; + } + + // get the limits of x + public double[] getLimits(){ + double[] limits = {this.xMin, this.xMax}; + return limits; + } + + // print to screen the limis of x + public void displayLimits(){ + System.out.println("\nThe limits of the abscissae (x-values) are " + this.xMin + " and " + this.xMax +"\n"); + } + + + // Checks for and removes all but one of identical points + // Checks and appropriately handles identical abscissae with differing ordinates + public void checkForIdenticalPoints(){ + int nP = this.nPoints; + boolean test1 = true; + int ii = 0; + while(test1){ + boolean test2 = true; + int jj = ii+1; + while(test2){ + if(this.x[ii]==this.x[jj]){ + if(this.y[ii]==this.y[jj]){ + System.out.print("CubicSpline: Two identical points, " + this.x[ii] + ", " + this.y[ii]); + System.out.println(", in data array at indices " + this.newAndOldIndices[ii] + " and " + this.newAndOldIndices[jj] + ", latter point removed"); + + for(int i=jj; i<nP-1; i++){ + this.x[i] = this.x[i+1]; + this.y[i] = this.y[i+1]; + this.newAndOldIndices[i-1] = this.newAndOldIndices[i]; + } + nP--; + for(int i=nP; i<this.nPoints; i++){ + this.x[i] = Double.NaN; + this.y[i] = Double.NaN; + this.newAndOldIndices[i-1] = -1000; + } + } + else{ + if(this.averageIdenticalAbscissae==true){ + System.out.print("CubicSpline: Two identical points on the absicca (x-axis) with different ordinate (y-axis) values, " + x[ii] + ": " + y[ii] + ", " + y[jj]); + System.out.println(", average of the ordinates taken"); + this.y[ii] = (this.y[ii] + this.y[jj])/2.0D; + for(int i=jj; i<nP-1; i++){ + this.x[i] = this.x[i+1]; + this.y[i] = this.y[i+1]; + this.newAndOldIndices[i-1] = this.newAndOldIndices[i]; + } + nP--; + for(int i=nP; i<this.nPoints; i++){ + this.x[i] = Double.NaN; + this.y[i] = Double.NaN; + this.newAndOldIndices[i-1] = -1000; + } + } + else{ + double sepn = range*0.0005D; + System.out.print("CubicSpline: Two identical points on the absicca (x-axis) with different ordinate (y-axis) values, " + x[ii] + ": " + y[ii] + ", " + y[jj]); + boolean check = false; + if(ii==0){ + if(x[2]-x[1]<=sepn)sepn = (x[2]-x[1])/2.0D; + if(this.y[0]>this.y[1]){ + if(this.y[1]>this.y[2]){ + check = stay(ii, jj, sepn); + } + else{ + check = swap(ii, jj, sepn); + } + } + else{ + if(this.y[2]<=this.y[1]){ + check = swap(ii, jj, sepn); + } + else{ + check = stay(ii, jj, sepn); + } + } + } + if(jj==nP-1){ + if(x[nP-2]-x[nP-3]<=sepn)sepn = (x[nP-2]-x[nP-3])/2.0D; + if(this.y[ii]<=this.y[jj]){ + if(this.y[ii-1]<=this.y[ii]){ + check = stay(ii, jj, sepn); + } + else{ + check = swap(ii, jj, sepn); + } + } + else{ + if(this.y[ii-1]<=this.y[ii]){ + check = swap(ii, jj, sepn); + } + else{ + check = stay(ii, jj, sepn); + } + } + } + if(ii!=0 && jj!=nP-1){ + if(x[ii]-x[ii-1]<=sepn)sepn = (x[ii]-x[ii-1])/2; + if(x[jj+1]-x[jj]<=sepn)sepn = (x[jj+1]-x[jj])/2; + if(this.y[ii]>this.y[ii-1]){ + if(this.y[jj]>this.y[ii]){ + if(this.y[jj]>this.y[jj+1]){ + if(this.y[ii-1]<=this.y[jj+1]){ + check = stay(ii, jj, sepn); + } + else{ + check = swap(ii, jj, sepn); + } + } + else{ + check = stay(ii, jj, sepn); + } + } + else{ + if(this.y[jj+1]>this.y[jj]){ + if(this.y[jj+1]>this.y[ii-1] && this.y[jj+1]>this.y[ii-1]){ + check = stay(ii, jj, sepn); + } + } + else{ + check = swap(ii, jj, sepn); + } + } + } + else{ + if(this.y[jj]>this.y[ii]){ + if(this.y[jj+1]>this.y[jj]){ + check = stay(ii, jj, sepn); + } + } + else{ + if(this.y[jj+1]>this.y[ii-1]){ + check = stay(ii, jj, sepn); + } + else{ + check = swap(ii, jj, sepn); + } + } + } + } + + if(check==false){ + check = stay(ii, jj, sepn); + } + System.out.println(", the two abscissae have been separated by a distance " + sepn); + jj++; + } + } + if((nP-1)==ii)test2 = false; + } + else{ + jj++; + } + if(jj>=nP)test2 = false; + } + ii++; + if(ii>=nP-1)test1 = false; + } + this.nPoints = nP; + if(this.nPoints<3)throw new IllegalArgumentException("Removal of duplicate points has reduced the number of points to less than the required minimum of three data points"); + + this.checkPoints = true; + } + + // Swap method for checkForIdenticalPoints procedure + private boolean swap(int ii, int jj, double sepn){ + this.x[ii] += sepn; + this.x[jj] -= sepn; + double hold = this.x[ii]; + this.x[ii] = this.x[jj]; + this.x[jj] = hold; + hold = this.y[ii]; + this.y[ii] = this.y[jj]; + this.y[jj] = hold; + return true; + } + + // Stay method for checkForIdenticalPoints procedure + private boolean stay(int ii, int jj, double sepn){ + this.x[ii] -= sepn; + this.x[jj] += sepn; + return true; + } + + // Returns a new CubicSpline setting array lengths to n and all array values to zero with natural spline default + // Primarily for use in BiCubicSpline + public static CubicSpline zero(int n){ + if(n<3)throw new IllegalArgumentException("A minimum of three data points is needed"); + CubicSpline aa = new CubicSpline(n); + return aa; + } + + // Create a one dimensional array of cubic spline objects of length n each of array length m + // Primarily for use in BiCubicSpline + public static CubicSpline[] oneDarray(int n, int m){ + if(m<3)throw new IllegalArgumentException("A minimum of three data points is needed"); + CubicSpline[] a =new CubicSpline[n]; + for(int i=0; i<n; i++){ + a[i]=CubicSpline.zero(m); + } + return a; + } + + // Enters the first derivatives of the cubic spline at + // the first and last point of the tabulated data + // Overrides a natural spline + public void setDerivLimits(double yp1, double ypn){ + this.yp1=yp1; + this.ypn=ypn; + } + + // Resets a natural spline + // Use above - this kept for backward compatibility + public void setDerivLimits(){ + this.yp1=Double.NaN; + this.ypn=Double.NaN; + } + + // Enters the first derivatives of the cubic spline at + // the first and last point of the tabulated data + // Overrides a natural spline + // Use setDerivLimits(double yp1, double ypn) - this kept for backward compatibility + public void setDeriv(double yp1, double ypn){ + this.yp1=yp1; + this.ypn=ypn; + this.derivCalculated = false; + } + + // Returns the internal array of second derivatives + public double[] getDeriv(){ + if(!this.derivCalculated)this.calcDeriv(); + return this.d2ydx2; + } + + // Sets the internal array of second derivatives + // Used primarily with BiCubicSpline + public void setDeriv(double[] deriv){ + this.d2ydx2 = deriv; + this.derivCalculated = true; + } + + // Calculates the second derivatives of the tabulated function + // for use by the cubic spline interpolation method (.interpolate) + // This method follows the procedure in Numerical Methods C language procedure for calculating second derivatives + public void calcDeriv(){ + double p=0.0D,qn=0.0D,sig=0.0D,un=0.0D; + double[] u = new double[nPoints]; + + if (Double.isNaN(this.yp1)){ + d2ydx2[0]=u[0]=0.0; + } + else{ + this.d2ydx2[0] = -0.5; + u[0]=(3.0/(this.x[1]-this.x[0]))*((this.y[1]-this.y[0])/(this.x[1]-this.x[0])-this.yp1); + } + + for(int i=1;i<=this.nPoints-2;i++){ + sig=(this.x[i]-this.x[i-1])/(this.x[i+1]-this.x[i-1]); + p=sig*this.d2ydx2[i-1]+2.0; + this.d2ydx2[i]=(sig-1.0)/p; + u[i]=(this.y[i+1]-this.y[i])/(this.x[i+1]-this.x[i]) - (this.y[i]-this.y[i-1])/(this.x[i]-this.x[i-1]); + u[i]=(6.0*u[i]/(this.x[i+1]-this.x[i-1])-sig*u[i-1])/p; + } + + if (Double.isNaN(this.ypn)){ + qn=un=0.0; + } + else{ + qn=0.5; + un=(3.0/(this.x[nPoints-1]-this.x[this.nPoints-2]))*(this.ypn-(this.y[this.nPoints-1]-this.y[this.nPoints-2])/(this.x[this.nPoints-1]-x[this.nPoints-2])); + } + + this.d2ydx2[this.nPoints-1]=(un-qn*u[this.nPoints-2])/(qn*this.d2ydx2[this.nPoints-2]+1.0); + for(int k=this.nPoints-2;k>=0;k--){ + this.d2ydx2[k]=this.d2ydx2[k]*this.d2ydx2[k+1]+u[k]; + } + this.derivCalculated = true; + } + + // INTERPOLATE + // Returns an interpolated value of y for a value of x from a tabulated function y=f(x) + // after the data has been entered via a constructor. + // The derivatives are calculated, bt calcDeriv(), on the first call to this method ands are + // then stored for use on all subsequent calls + public double interpolate(double xx){ + + if(!this.checkPoints)this.checkForIdenticalPoints(); + // Check for violation of interpolation bounds + if (xx<this.x[0]){ + // if violation is less than potntial rounding error - amend to lie with bounds + if(CubicSpline.roundingCheck && Math.abs(x[0]-xx)<=Math.pow(10, Math.floor(Math.log10(Math.abs(this.x[0]))))*CubicSpline.potentialRoundingError){ + xx = x[0]; + } + else{ + throw new IllegalArgumentException("x ("+xx+") is outside the range of data points ("+x[0]+" to "+x[this.nPoints-1] + ")"); + } + } + if (xx>this.x[this.nPoints-1]){ + if(CubicSpline.roundingCheck && Math.abs(xx-this.x[this.nPoints-1])<=Math.pow(10, Math.floor(Math.log10(Math.abs(this.x[this.nPoints-1]))))*CubicSpline.potentialRoundingError){ + xx = this.x[this.nPoints-1]; + } + else{ + throw new IllegalArgumentException("x ("+xx+") is outside the range of data points ("+x[0]+" to "+x[this.nPoints-1] + ")"); + } + } + + if(!this.derivCalculated)this.calcDeriv(); + + double h=0.0D,b=0.0D,a=0.0D, yy=0.0D; + int k=0; + int klo=0; + int khi=this.nPoints-1; + while (khi-klo > 1){ + k=(khi+klo) >> 1; + if(this.x[k] > xx){ + khi=k; + } + else{ + klo=k; + } + } + h=this.x[khi]-this.x[klo]; + + if (h == 0.0){ + throw new IllegalArgumentException("Two values of x are identical: point "+klo+ " ("+this.x[klo]+") and point "+khi+ " ("+this.x[khi]+")" ); + } + else{ + a=(this.x[khi]-xx)/h; + b=(xx-this.x[klo])/h; + yy=a*this.y[klo]+b*this.y[khi]+((a*a*a-a)*this.d2ydx2[klo]+(b*b*b-b)*this.d2ydx2[khi])*(h*h)/6.0; + } + return yy; + } + + // Returns an interpolated value of y for a value of x (xx) from a tabulated function y=f(x) + // after the derivatives (deriv) have been calculated independently of calcDeriv(). + public static double interpolate(double xx, double[] x, double[] y, double[] deriv){ + + if(((x.length != y.length) || (x.length != deriv.length)) || (y.length != deriv.length)){ + throw new IllegalArgumentException("array lengths are not all equal"); + } + int n = x.length; + double h=0.0D, b=0.0D, a=0.0D, yy = 0.0D; + + int k=0; + int klo=0; + int khi=n-1; + while(khi-klo > 1){ + k=(khi+klo) >> 1; + if(x[k] > xx){ + khi=k; + } + else{ + klo=k; + } + } + h=x[khi]-x[klo]; + + if (h == 0.0){ + throw new IllegalArgumentException("Two values of x are identical"); + } + else{ + a=(x[khi]-xx)/h; + b=(xx-x[klo])/h; + yy=a*y[klo]+b*y[khi]+((a*a*a-a)*deriv[klo]+(b*b*b-b)*deriv[khi])*(h*h)/6.0; + } + return yy; + } + +} diff --git a/src/main/java/flanagan/interpolation/PolyCubicSpline.java b/src/main/java/flanagan/interpolation/PolyCubicSpline.java new file mode 100755 index 0000000000000000000000000000000000000000..0d4f8a78ddcb9b4939f27bd509e40ff0492b7ac6 --- /dev/null +++ b/src/main/java/flanagan/interpolation/PolyCubicSpline.java @@ -0,0 +1,282 @@ +/********************************************************** +* +* PolyCubicSpline.java +* +* Class for performing an interpolation on the tabulated +* function y = f(x1,x2, x3 .... xn) using a natural cubic splines +* Assumes second derivatives at end points = 0 (natural spines) +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 15 February 2006, +* UPDATES: 9 June 2007, 27 July 2007, 4 December 2007, 21 September 2008, 12 October 2009, 31 October 2009 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/PolyCubicSpline.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2006 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + + +package flanagan.interpolation; + +import flanagan.math.Fmath; +import java.lang.reflect.Array; + +public class PolyCubicSpline{ + + private int nDimensions = 0; // number of the dimensions of the tabulated points array, y=f(x1,x2,x3 . . xn), i.e. n + private Object fOfX = null; // tabulated values of y = f(x1,x2,x3 . . fn) + // as a multidimensional array of double [x1 length][x2 length] ... [xn length] + private Object internalDeriv = null; // Object to store second derivatives + // as a multidimensional array of Objects the innermost three layers being double arrays + private Object xArrays = null; // The variable arrays x1, x2, x3 . . . xn + // packed as an Object as a multidimensional array of double [][] + // where xArrays[0] = array of x1 values, xArrays[1] = array of x2 values etc + private Object method = null; // interpolation method + private double[][] xArray = null; // The variable arrays x1, x2, x3 . . . xn + private double[] csArray = null; // array for final cubic spline interpolation + private PolyCubicSpline[] pcs = null; // array of PolyCubicSplines for use with recursive step + private int dimOne = 0; // xArray dimension in a recursive step + + private double yValue = 0.0D; // returned interpolated value + private double[] xMin = null; // minimum values of the x arrays + private double[] xMax = null; // maximum values of the x arrays + private boolean calculationDone = false; // = true when derivatives calculated + private boolean averageIdenticalAbscissae = false; // if true: the the ordinate values for identical abscissae are averaged + // If false: the abscissae values are separated by 0.001 of the total abscissae range; + private static double potentialRoundingError = 5e-15; // potential rounding error used in checking wheter a value lies within the interpolation bounds (static value) + private static boolean roundingCheck = true; // = true: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit (static value) + + + // Constructor + public PolyCubicSpline(Object xArrays, Object fOfX){ + + this.fOfX = Fmath.copyObject(fOfX); + this.xArrays = Fmath.copyObject(xArrays); + + // Calculate fOfX array dimension number + Object internalArrays = Fmath.copyObject(fOfX); + this.nDimensions = 1; + while(!((internalArrays = Array.get(internalArrays, 0)) instanceof Double))this.nDimensions++; + + // Repack xArrays as 2 dimensional array if entered a single dimensioned array for a simple cubic spline + if(this.xArrays instanceof double[] && this.nDimensions == 1){ + double[][] xArraysTemp = new double[1][]; + xArraysTemp[0] = (double[])this.xArrays; + this.xArrays = (Object)xArraysTemp; + } + else{ + if(!(this.xArrays instanceof double[][]))throw new IllegalArgumentException("xArrays should be a two dimensional array of doubles"); + } + + // x -arrays and their limits + this.xArray = (double[][])this.xArrays; + this.limits(); + + // Select interpolation method + switch(this.nDimensions){ + case 0: throw new IllegalArgumentException("data array must have at least one dimension"); + case 1: // If fOfX is one dimensional perform simple cubic spline + CubicSpline cs = new CubicSpline(this.xArray[0], (double[])this.fOfX); + if(this.averageIdenticalAbscissae)cs.averageIdenticalAbscissae(); + this.internalDeriv = (Object)(cs.getDeriv()); + this.method = (Object)cs; + this.calculationDone = true; + break; + case 2: // If fOfX is two dimensional perform bicubic spline + BiCubicSpline bcs = new BiCubicSpline(this.xArray[0], this.xArray[1], (double[][])this.fOfX); + if(this.averageIdenticalAbscissae)bcs.averageIdenticalAbscissae(); + this.internalDeriv = (Object)(bcs.getDeriv()); + this.method = (Object)bcs; + this.calculationDone = true; + break; + case 3: // If fOfX is three dimensional perform tricubic spline + TriCubicSpline tcs = new TriCubicSpline(xArray[0], xArray[1], xArray[2], (double[][][])this.fOfX); + if(this.averageIdenticalAbscissae)tcs.averageIdenticalAbscissae(); + this.internalDeriv = (Object)(tcs.getDeriv()); + this.method = (Object)tcs; + this.calculationDone = true; + break; + case 4: // If fOfX is four dimensional perform quadricubic spline + QuadriCubicSpline qcs = new QuadriCubicSpline(xArray[0], xArray[1], xArray[2], xArray[3], (double[][][][])this.fOfX); + if(this.averageIdenticalAbscissae)qcs.averageIdenticalAbscissae(); + this.internalDeriv = (Object)(qcs.getDeriv()); + this.method = (Object)qcs; + this.calculationDone = true; + break; + default: // If fOfX is greater than four dimensional, recursively call PolyCubicSpline + // with, as arguments, the n1 fOfX sub-arrays, each of (number of dimensions - 1) dimensions, + // where n1 is the number of x1 variables. + Object obj = fOfX; + this.dimOne = Array.getLength(obj); + this.csArray = new double [dimOne]; + double[][] newXarrays= new double[this.nDimensions-1][]; + for(int i=0; i<this.nDimensions-1; i++){ + newXarrays[i] = xArray[i+1]; + } + + Object[] objDeriv = new Object[dimOne]; + if(calculationDone)objDeriv = (Object[])this.internalDeriv; + this.pcs = new PolyCubicSpline[dimOne]; + for(int i=0; i<dimOne; i++){ + Object objT = (Object)Array.get(obj, i); + this.pcs[i] = new PolyCubicSpline(newXarrays, objT); + if(this.averageIdenticalAbscissae)pcs[i].averageIdenticalAbscissae(); + if(this.calculationDone)pcs[i].setDeriv(objDeriv[i]); + if(!this.calculationDone)objDeriv[i] = pcs[i].getDeriv(); + } + this.internalDeriv = (Object)objDeriv; + this.calculationDone = true; + } + + } + + // Reset rounding error check option + // Default option: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit + // This method causes this check to be ignored and an exception to be thrown if any point lies outside the interpolation bounds + public static void noRoundingErrorCheck(){ + PolyCubicSpline.roundingCheck = false; + QuadriCubicSpline.noRoundingErrorCheck(); + TriCubicSpline.noRoundingErrorCheck(); + BiCubicSpline.noRoundingErrorCheck(); + CubicSpline.noRoundingErrorCheck(); + } + + // Reset potential rounding error value + // Default option: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit + // The default value for the potential rounding error is 5e-15*times the 10^exponent of the value outside the bounds + // This method allows the 5e-15 to be reset + public static void potentialRoundingError(double potentialRoundingError){ + PolyCubicSpline.potentialRoundingError = potentialRoundingError; + QuadriCubicSpline.potentialRoundingError(potentialRoundingError); + TriCubicSpline.potentialRoundingError(potentialRoundingError); + BiCubicSpline.potentialRoundingError(potentialRoundingError); + CubicSpline.potentialRoundingError(potentialRoundingError); + } + + // Limits to x arrays + private void limits(){ + this.xMin = new double[this.nDimensions]; + this.xMax = new double[this.nDimensions]; + for(int i=0; i<this.nDimensions; i++){ + this.xMin[i] = Fmath.minimum(xArray[i]); + this.xMax[i] = Fmath.maximum(xArray[i]); + } + } + + // Get minimum limits + public double[] getXmin(){ + return this.xMin; + } + + // Get maximum limits + public double[] getXmax(){ + return this.xMax; + } + + // Get number of dimensions + public int getNumberOfDimensions(){ + return this.nDimensions; + } + + // Get limits to x + public double[] getLimits(){ + double[] limits = new double[2*this.nDimensions]; + int j = 0; + for(int i=0; i<this.nDimensions; i++){ + limits[j] = this.xMin[i]; + j++; + limits[j] = this.xMax[i]; + j++; + } + return limits; + } + + // Display limits to x + public void displayLimits(){ + System.out.println(" "); + for(int i=0; i<this.nDimensions; i++){ + System.out.println("The limits to the x array " + i + " are " + xMin[i] + " and " + xMax[i]); + } + System.out.println(" "); + } + + // Reset the default handing of identical abscissae with different ordinates + // from the default option of separating the two relevant abscissae by 0.001 of the range + // to avraging the relevant ordinates + public void averageIdenticalAbscissae(){ + this.averageIdenticalAbscissae = true; + } + + // Interpolation method + public double interpolate(double[] unknownCoord){ + + int nUnknown = unknownCoord.length; + if(nUnknown!=this.nDimensions)throw new IllegalArgumentException("Number of unknown value coordinates, " + nUnknown + ", does not equal the number of tabulated data dimensions, " + this.nDimensions); + + switch(this.nDimensions){ + case 0: throw new IllegalArgumentException("data array must have at least one dimension"); + case 1: // If fOfX is one dimensional perform simple cubic spline + this.yValue = ((CubicSpline)(this.method)).interpolate(unknownCoord[0]); + break; + case 2: // If fOfX is two dimensional perform bicubic spline + this.yValue = ((BiCubicSpline)(this.method)).interpolate(unknownCoord[0], unknownCoord[1]); + break; + case 3: // If fOfX is three dimensional perform tricubic spline + this.yValue = ((TriCubicSpline)(this.method)).interpolate(unknownCoord[0], unknownCoord[1], unknownCoord[2]); + break; + case 4: // If fOfX is four dimensional perform quadricubic spline + this.yValue = ((QuadriCubicSpline)(this.method)).interpolate(unknownCoord[0], unknownCoord[1], unknownCoord[2], unknownCoord[2]); + break; + default: // If fOfX is greater than four dimensional, recursively call PolyCubicSpline + // with, as arguments, the n1 fOfX sub-arrays, each of (number of dimensions - 1) dimensions, + // where n1 is the number of x1 variables. + double[] newCoord = new double[this.nDimensions-1]; + for(int i=0; i<this.nDimensions-1; i++){ + newCoord[i] = unknownCoord[i+1]; + } + for(int i=0; i<this.dimOne; i++){ + csArray[i] = pcs[i].interpolate(newCoord); + } + + // Perform simple cubic spline on the array of above returned interpolates + CubicSpline ncs = new CubicSpline(this.xArray[0], this.csArray); + this.yValue = ncs.interpolate(unknownCoord[0]); + } + + return this.yValue; + } + + // Set derivatives (internal array) + public void setDeriv(Object internalDeriv){ + this.internalDeriv = internalDeriv; + } + + // Get derivatives (internal array) + public Object getDeriv(){ + return this.internalDeriv; + } + + +} + diff --git a/src/main/java/flanagan/interpolation/QuadriCubicSpline.java b/src/main/java/flanagan/interpolation/QuadriCubicSpline.java new file mode 100755 index 0000000000000000000000000000000000000000..24a0a8f6f533005633050ec33575d28786221dd0 --- /dev/null +++ b/src/main/java/flanagan/interpolation/QuadriCubicSpline.java @@ -0,0 +1,223 @@ +/********************************************************** +* +* QuadriCubicSpline.java +* +* Class for performing an interpolation on the tabulated +* function y = f(x1,x2,x3,x4) using a natural quadricubic spline +* Assumes second derivatives at end points = 0 (natural spine) +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: May 2003 +* UPDATE July 2007, 4 December 2007, 21 September 2008, 12 October 2009, 31 October 2009 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/QuadriCubicSpline.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.interpolation; + +import flanagan.math.Fmath; + +public class QuadriCubicSpline{ + + private int nPoints = 0; // no. of x1 tabulated points + private int mPoints = 0; // no. of x2 tabulated points + private int lPoints = 0; // no. of x3 tabulated points + private int kPoints = 0; // no. of x4 tabulated points + + private double[][][][] y = null; // y=f(x1,x2,x3,x4) tabulated function + private double[] x1 = null; // x1 in tabulated function f(x1,x2,x3,x4) + private double[] x2 = null; // x2 in tabulated function f(x1,x2,x3,x4) + private double[] x3 = null; // x3 in tabulated function f(x1,x2,x3,x4) + private double[] x4 = null; // x4 in tabulated function f(x1,x2,x3,x4) + private double[] xMin = new double[4]; // minimum values of x1, x2, x3 and x4 + private double[] xMax = new double[4]; // maximum values of x1, x2, x3 and x4 + + private TriCubicSpline[] tcsn = null; // nPoints array of TriCubicSpline instances + private CubicSpline csm = null; // CubicSpline instance + private double[][][][] d2ydx2inner = null; // inner matrix of second derivatives + private boolean derivCalculated = false; // = true when the called triicubic spline derivatives have been calculated + private boolean averageIdenticalAbscissae = false; // if true: the the ordinate values for identical abscissae are averaged + // If false: the abscissae values are separated by 0.001 of the total abscissae range; + private static double potentialRoundingError = 5e-15; // potential rounding error used in checking wheter a value lies within the interpolation bounds (static value) + private static boolean roundingCheck = true; // = true: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit (static value) + + + // Constructor + public QuadriCubicSpline(double[] x1, double[] x2, double[] x3, double[] x4, double[][][][] y){ + this.nPoints=x1.length; + this.mPoints=x2.length; + this.lPoints=x3.length; + this.kPoints=x4.length; + if(this.nPoints!=y.length)throw new IllegalArgumentException("Arrays x1 and y-row are of different length " + this.nPoints + " " + y.length); + if(this.mPoints!=y[0].length)throw new IllegalArgumentException("Arrays x2 and y-column are of different length "+ this.mPoints + " " + y[0].length); + if(this.lPoints!=y[0][0].length)throw new IllegalArgumentException("Arrays x3 and y-column are of different length "+ this.mPoints + " " + y[0][0].length); + if(this.kPoints!=y[0][0][0].length)throw new IllegalArgumentException("Arrays x4 and y-column are of different length "+ this.kPoints + " " + y[0][0][0].length); + if(this.nPoints<3 || this.mPoints<3 || this.lPoints<3 || this.kPoints<3)throw new IllegalArgumentException("The tabulated 4D array must have a minimum size of 3 X 3 X 3 X 3"); + + this.csm = new CubicSpline(this.nPoints); + this.tcsn = TriCubicSpline.oneDarray(this.nPoints, this.mPoints, this.lPoints, this.kPoints); + this.x1 = new double[this.nPoints]; + this.x2 = new double[this.mPoints]; + this.x3 = new double[this.lPoints]; + this.x4 = new double[this.kPoints]; + + this.y = new double[this.nPoints][this.mPoints][this.lPoints][this.kPoints]; + this.d2ydx2inner = new double[this.nPoints][this.mPoints][this.lPoints][this.kPoints]; + for(int i=0; i<this.nPoints; i++){ + this.x1[i]=x1[i]; + } + this.xMin[0] = Fmath.minimum(this.x1); + this.xMax[0] = Fmath.maximum(this.x1); + + for(int j=0; j<this.mPoints; j++){ + this.x2[j]=x2[j]; + } + this.xMin[1] = Fmath.minimum(this.x2); + this.xMax[1] = Fmath.maximum(this.x2); + + for(int j=0; j<this.lPoints; j++){ + this.x3[j]=x3[j]; + } + this.xMin[2] = Fmath.minimum(this.x3); + this.xMax[2] = Fmath.maximum(this.x3); + + for(int j=0; j<this.kPoints; j++){ + this.x4[j]=x4[j]; + } + this.xMin[3] = Fmath.minimum(this.x4); + this.xMax[3] = Fmath.maximum(this.x4); + + for(int i =0; i<this.nPoints; i++){ + for(int j=0; j<this.mPoints; j++){ + for(int k=0; k<this.lPoints; k++){ + for(int l=0; l<this.kPoints; l++){ + this.y[i][j][k][l]=y[i][j][k][l]; + } + } + } + } + + double[][][] yTempml = new double[this.mPoints][this.lPoints][this.kPoints]; + for(int i=0; i<this.nPoints; i++){ + for(int j=0; j<this.mPoints; j++){ + for(int k=0; k<this.lPoints; k++){ + for(int l=0; l<this.kPoints; l++){ + yTempml[j][k][l]=y[i][j][k][l]; + } + } + } + this.tcsn[i].resetData(x2,x3,x4,yTempml); + d2ydx2inner[i] = this.tcsn[i].getDeriv(); + } + double[] yTempm = new double[nPoints]; + this.derivCalculated = true; + } + + // METHODS + + // Reset rounding error check option + // Default option: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit + // This method causes this check to be ignored and an exception to be thrown if any point lies outside the interpolation bounds + public static void noRoundingErrorCheck(){ + QuadriCubicSpline.roundingCheck = false; + TriCubicSpline.noRoundingErrorCheck(); + BiCubicSpline.noRoundingErrorCheck(); + CubicSpline.noRoundingErrorCheck(); + } + + // Reset potential rounding error value + // Default option: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit + // The default value for the potential rounding error is 5e-15*times the 10^exponent of the value outside the bounds + // This method allows the 5e-15 to be reset + public static void potentialRoundingError(double potentialRoundingError){ + QuadriCubicSpline.potentialRoundingError = potentialRoundingError; + TriCubicSpline.potentialRoundingError(potentialRoundingError); + BiCubicSpline.potentialRoundingError(potentialRoundingError); + CubicSpline.potentialRoundingError(potentialRoundingError); + } + + // Reset the default handing of identical abscissae with different ordinates + // from the default option of separating the two relevant abscissae by 0.001 of the range + // to avraging the relevant ordinates + public void averageIdenticalAbscissae(){ + this.averageIdenticalAbscissae = true; + for(int i=0; i<this.tcsn.length; i++)this.tcsn[i].averageIdenticalAbscissae(); + this.csm.averageIdenticalAbscissae(); + } + + // Get minimum limits + public double[] getXmin(){ + return this.xMin; + } + + // Get maximum limits + public double[] getXmax(){ + return this.xMax; + } + + // Get limits to x + public double[] getLimits(){ + double[] limits = {xMin[0], xMax[0], xMin[1], xMax[1], xMin[2], xMax[2], xMin[3], xMax[3]}; + return limits; + } + + // Display limits to x + public void displayLimits(){ + System.out.println(" "); + for(int i=0; i<2; i++){ + System.out.println("The limits to the x array " + i + " are " + xMin[i] + " and " + xMax[i]); + } + System.out.println(" "); + } + + // Returns an interpolated value of y for values of x1, x2, x3 and x4 + // from a tabulated function y=f(x1,x2,x3,x4) + public double interpolate(double xx1, double xx2, double xx3, double xx4){ + + + double[] yTempm = new double[nPoints]; + for (int i=0;i<nPoints;i++){ + yTempm[i]=this.tcsn[i].interpolate(xx2, xx3, xx4); + } + this.csm.resetData(x1,yTempm); + return this.csm.interpolate(xx1); + } + + + // Get inner matrix of derivatives + // Primarily used by PolyCubicSpline + public double[][][][] getDeriv(){ + return this.d2ydx2inner; + } + + // Set inner matrix of derivatives + // Primarily used by PolyCubicSpline + public void setDeriv(double[][][][] d2ydx2){ + this.d2ydx2inner = d2ydx2; + this.derivCalculated = true; + } +} + diff --git a/src/main/java/flanagan/interpolation/TriCubicSpline.java b/src/main/java/flanagan/interpolation/TriCubicSpline.java new file mode 100755 index 0000000000000000000000000000000000000000..1634527d7cd05398db2865bab1d1bb02b7dcbbf7 --- /dev/null +++ b/src/main/java/flanagan/interpolation/TriCubicSpline.java @@ -0,0 +1,283 @@ +/********************************************************** +* +* TriCubicSpline.java +* +* Class for performing an interpolation on the tabulated +* function y = f(x1,x2,x3) using a natural tricubic spline +* Assumes second derivatives at end points = 0 (natural spine) +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: May 2002 +* UPDATE: 20 May 2003, 17 February 2006, 27 July 2007, 4 December 2007, 31 October 2009 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/TriCubicSpline.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at http:\\www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.interpolation; + +import flanagan.math.Fmath; + +public class TriCubicSpline{ + + private int nPoints = 0; // no. of x1 tabulated points + private int mPoints = 0; // no. of x2 tabulated points + private int lPoints = 0; // no. of x3 tabulated points + private double[][][] y = null; // y=f(x1,x2) tabulated function + private double[] x1 = null; // x1 in tabulated function f(x1,x2,x3) + private double[] x2 = null; // x2 in tabulated function f(x1,x2,x3) + private double[] x3 = null; // x3 in tabulated function f(x1,x2,x3) + private double[] xMin = new double[3]; // minimum values of x1, x2 and x3 + private double[] xMax = new double[3]; // maximum values of x1, x2 and x3 + private BiCubicSpline[] bcsn = null; // nPoints array of BiCubicSpline instances + private CubicSpline csm = null; // CubicSpline instance + private double[][][] d2ydx2inner = null; // inner matrix of second derivatives + private boolean derivCalculated = false; // = true when the called bicubic spline derivatives have been calculated + private boolean averageIdenticalAbscissae = false; // if true: the the ordinate values for identical abscissae are averaged + // If false: the abscissae values are separated by 0.001 of the total abscissae range; + private static double potentialRoundingError = 5e-15; // potential rounding error used in checking wheter a value lies within the interpolation bounds (static value) + private static boolean roundingCheck = true; // = true: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit (static value) + + + // Constructor + public TriCubicSpline(double[] x1, double[] x2, double[] x3, double[][][] y){ + this.nPoints=x1.length; + this.mPoints=x2.length; + this.lPoints=x3.length; + if(this.nPoints!=y.length)throw new IllegalArgumentException("Arrays x1 and y-row are of different length " + this.nPoints + " " + y.length); + if(this.mPoints!=y[0].length)throw new IllegalArgumentException("Arrays x2 and y-column are of different length "+ this.mPoints + " " + y[0].length); + if(this.lPoints!=y[0][0].length)throw new IllegalArgumentException("Arrays x3 and y-column are of different length "+ this.mPoints + " " + y[0][0].length); + if(this.nPoints<3 || this.mPoints<3 || this.lPoints<3)throw new IllegalArgumentException("The tabulated 3D array must have a minimum size of 3 X 3 X 3"); + + this.csm = new CubicSpline(this.nPoints); + this.bcsn = BiCubicSpline.oneDarray(this.nPoints, this.mPoints, this.lPoints); + this.x1 = new double[this.nPoints]; + this.x2 = new double[this.mPoints]; + this.x3 = new double[this.lPoints]; + this.y = new double[this.nPoints][this.mPoints][this.lPoints]; + this.d2ydx2inner = new double[this.nPoints][this.mPoints][this.lPoints]; + for(int i=0; i<this.nPoints; i++){ + this.x1[i]=x1[i]; + } + this.xMin[0] = Fmath.minimum(this.x1); + this.xMax[0] = Fmath.maximum(this.x1); + for(int j=0; j<this.mPoints; j++){ + this.x2[j]=x2[j]; + } + this.xMin[1] = Fmath.minimum(this.x2); + this.xMax[1] = Fmath.maximum(this.x2); + for(int j=0; j<this.lPoints; j++){ + this.x3[j]=x3[j]; + } + this.xMin[2] = Fmath.minimum(this.x3); + this.xMax[2] = Fmath.maximum(this.x3); + for(int i =0; i<this.nPoints; i++){ + for(int j=0; j<this.mPoints; j++){ + for(int k=0; k<this.lPoints; k++){ + this.y[i][j][k]=y[i][j][k]; + } + } + } + + double[][] yTempml = new double[this.mPoints][this.lPoints]; + for(int i=0; i<this.nPoints; i++){ + + for(int j=0; j<this.mPoints; j++){ + for(int k=0; k<this.lPoints; k++){ + yTempml[j][k]=y[i][j][k]; + } + } + this.bcsn[i].resetData(x2,x3,yTempml); + this.d2ydx2inner[i] = this.bcsn[i].getDeriv(); + } + derivCalculated = true; + } + + // Constructor with data arrays initialised to zero + // Primarily for use by QuadriCubicSpline + public TriCubicSpline(int nP, int mP, int lP){ + this.nPoints=nP; + this.mPoints=mP; + this.lPoints=lP; + if(this.nPoints<3 || this.mPoints<3 || this.lPoints<3)throw new IllegalArgumentException("The data matrix must have a minimum size of 3 X 3 X 3"); + + this.csm = new CubicSpline(this.nPoints); + this.bcsn = BiCubicSpline.oneDarray(this.nPoints, this.mPoints, this.lPoints); + this.x1 = new double[this.nPoints]; + this.x2 = new double[this.mPoints]; + this.x3 = new double[this.lPoints]; + this.y = new double[this.nPoints][this.mPoints][this.lPoints]; + this.d2ydx2inner = new double[this.nPoints][this.mPoints][this.lPoints]; + } + + // METHODS + + // Reset rounding error check option + // Default option: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit + // This method causes this check to be ignored and an exception to be thrown if any point lies outside the interpolation bounds + public static void noRoundingErrorCheck(){ + TriCubicSpline.roundingCheck = false; + BiCubicSpline.noRoundingErrorCheck(); + CubicSpline.noRoundingErrorCheck(); + } + + // Reset potential rounding error value + // Default option: points outside the interpolation bounds by less than the potential rounding error rounded to the bounds limit + // The default value for the potential rounding error is 5e-15*times the 10^exponent of the value outside the bounds + // This method allows the 5e-15 to be reset + public static void potentialRoundingError(double potentialRoundingError){ + TriCubicSpline.potentialRoundingError = potentialRoundingError; + BiCubicSpline.potentialRoundingError(potentialRoundingError); + CubicSpline.potentialRoundingError(potentialRoundingError); + } + + // Reset the default handing of identical abscissae with different ordinates + // from the default option of separating the two relevant abscissae by 0.001 of the range + // to avraging the relevant ordinates + public void averageIdenticalAbscissae(){ + this.averageIdenticalAbscissae = true; + for(int i=0; i<this.bcsn.length; i++)this.bcsn[i].averageIdenticalAbscissae(); + this.csm.averageIdenticalAbscissae(); + } + + // Returns a new TriCubicSpline setting internal array size to nP x mP x lP and all array values to zero with natural spline default + // Primarily for use in this.oneDarray for QuadriCubicSpline + public static TriCubicSpline zero(int nP, int mP, int lP){ + if(nP<3 || mP<3 || lP<3)throw new IllegalArgumentException("A minimum of three x three x three data points is needed"); + TriCubicSpline aa = new TriCubicSpline(nP, mP, lP); + return aa; + } + + // Create a one dimensional array of TriCubicSpline objects of length nP each of internal array size mP x lP xkP + // Primarily for use in quadriCubicSpline + public static TriCubicSpline[] oneDarray(int nP, int mP, int lP, int kP){ + if(mP<3 || lP<3 || kP<3)throw new IllegalArgumentException("A minimum of three x three x three data points is needed"); + TriCubicSpline[] a = new TriCubicSpline[nP]; + for(int i=0; i<nP; i++){ + a[i]=TriCubicSpline.zero(mP, lP, kP); + } + return a; + } + + + // Resets the x1, x2, x3, y data arrays + // Primarily for use in QuadriCubicSpline + public void resetData(double[] x1, double[] x2, double[] x3, double[][][] y){ + if(x1.length!=y.length)throw new IllegalArgumentException("Arrays x1 and y row are of different length"); + if(x2.length!=y[0].length)throw new IllegalArgumentException("Arrays x2 and y column are of different length"); + if(x3.length!=y[0][0].length)throw new IllegalArgumentException("Arrays x3 and y column are of different length"); + if(this.nPoints!=x1.length)throw new IllegalArgumentException("Original array length not matched by new array length"); + if(this.mPoints!=x2.length)throw new IllegalArgumentException("Original array length not matched by new array length"); + if(this.lPoints!=x3.length)throw new IllegalArgumentException("Original array length not matched by new array length"); + + for(int i=0; i<this.nPoints; i++){ + this.x1[i]=x1[i]; + } + this.xMin[0] = Fmath.minimum(this.x1); + this.xMax[0] = Fmath.maximum(this.x1); + + for(int i=0; i<this.mPoints; i++){ + this.x2[i]=x2[i]; + } + this.xMin[1] = Fmath.minimum(this.x2); + this.xMax[1] = Fmath.maximum(this.x2); + + for(int i=0; i<this.lPoints; i++){ + this.x3[i]=x3[i]; + } + this.xMin[2] = Fmath.minimum(this.x3); + this.xMax[2] = Fmath.maximum(this.x3); + + for(int i=0; i<this.nPoints; i++){ + for(int j=0; j<this.mPoints; j++){ + for(int k=0; k<this.lPoints; k++){ + this.y[i][j][k]=y[i][j][k]; + } + } + } + + this.csm = new CubicSpline(this.nPoints); + this.bcsn = BiCubicSpline.oneDarray(this.nPoints, this.mPoints, this.lPoints); + double[][] yTempml = new double[this.mPoints][this.lPoints]; + for(int i=0; i<this.nPoints; i++){ + + for(int j=0; j<this.mPoints; j++){ + for(int k=0; k<this.lPoints; k++){ + yTempml[j][k]=y[i][j][k]; + } + } + this.bcsn[i].resetData(x2,x3,yTempml); + this.d2ydx2inner[i] = this.bcsn[i].getDeriv(); + } + derivCalculated = true; + } + + // Get minimum limits + public double[] getXmin(){ + return this.xMin; + } + + // Get maximum limits + public double[] getXmax(){ + return this.xMax; + } + + // Get limits to x + public double[] getLimits(){ + double[] limits = {xMin[0], xMax[0], xMin[1], xMax[1], xMin[2], xMax[2]}; + return limits; + } + + // Display limits to x + public void displayLimits(){ + System.out.println(" "); + for(int i=0; i<3; i++){ + System.out.println("The limits to the x array " + i + " are " + xMin[i] + " and " + xMax[i]); + } + System.out.println(" "); + } + + // Returns an interpolated value of y for values of x1, x2 and x3 + // from a tabulated function y=f(x1,x2,x3) + public double interpolate(double xx1, double xx2, double xx3){ + + double[] yTempm = new double[nPoints]; + + for (int i=0;i<nPoints;i++){ + yTempm[i]=this.bcsn[i].interpolate(xx2, xx3); + } + + this.csm.resetData(x1,yTempm); + return this.csm.interpolate(xx1); + } + + // Get inner matrix of derivatives + // Primarily used by QuadriCubicSpline + public double[][][] getDeriv(){ + return this.d2ydx2inner; + } + + // Set inner matrix of derivatives + // Primarily used by QuadriCubicSpline + public void setDeriv(double[][][] d2ydx2){ + this.d2ydx2inner = d2ydx2; + this.derivCalculated = true; + } +} + diff --git a/src/main/java/flanagan/io/Db.java b/src/main/java/flanagan/io/Db.java new file mode 100755 index 0000000000000000000000000000000000000000..c6a48b854ae9dd706f64284c729517674a31f6d4 --- /dev/null +++ b/src/main/java/flanagan/io/Db.java @@ -0,0 +1,1621 @@ +/* +* Class Db +* +* Methods for entering doubles, floats, integers, +* long integers, strings, chars, Complexes and Phasors +* from the key board via the standard console window +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 19 June 2003 +* MODIFIED: 25 June 2005, 27 June 2007, 21/22 July 2007 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Db.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) June 2003, July 2007 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + + +package flanagan.io; + +import java.io.*; +import java.math.*; +import javax.swing.JOptionPane; + +import flanagan.analysis.ErrorProp; +import flanagan.complex.Complex; +import flanagan.complex.ComplexErrorProp; +import flanagan.circuits.Phasor; +import flanagan.math.Fmath; + +public class Db +{ + // Reads a double from a dialog box with a prompt message + // No default option + public static final synchronized double readDouble(String mess){ + String line=""; + double d=0.0D; + boolean finish = false; + System.out.flush(); + String mess0 = "Input type: double\n"; + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess); + if(line!=null){ + try{ + d = Double.parseDouble(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid double not entered - dialog box recalled + } + } + } + return d; + } + + // Reads a double from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed + public static final synchronized double readDouble(String mess, double dflt){ + String line=""; + double d=0.0D; + boolean finish = false; + System.out.flush(); + String mess0 = "Input type: double\n"; + mess = mess + "\n"; + String dfltmess = dflt + ""; + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + d=dflt; + finish=true; + line=null; + } + else{ + try{ + d = Double.parseDouble(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid double not entered - dialog box recalled + } + } + } + } + return d; + } + + // Reads a double from the dialog box + // No prompt message, No default option + public static final synchronized double readDouble(){ + String line=""; + String mess="Input type: double"; + double d=0.0D; + boolean finish = false; + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess); + if(line!=null){ + try{ + d = Double.parseDouble(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid double not entered - dialog box recalled + } + } + } + return d; + } + + // Read a Complex number from dialog box with a prompt message + // in a String format compatible with Complex.parse, + // e.g 2+j3, 2 + j3, 2+i3, 2 + i3 + // No default option + public static final synchronized Complex readComplex(String mess){ + String line=""; + Complex c = new Complex(); + boolean finish = false; + String mess0 = "Input type: Complex (x + jy)\n"; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess); + if(line!=null){ + try{ + c = Complex.parseComplex(line); + finish=true; + }catch(NumberFormatException e){ + // Valid double not entered - dialog box recalled + } + } + } + return c; + } + + // Reads a Complex from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed - Complex default + public static final synchronized Complex readComplex(String mess, Complex dflt){ + String line=""; + Complex c = new Complex(); + boolean finish = false; + String mess0 = "Input type: Complex (x + jy)\n"; + String dfltmess = dflt+""; + mess = mess + "\n"; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + c = dflt; + finish=true; + line=null; + } + else{ + try{ + c = Complex.parseComplex(line); + finish=true; + }catch(NumberFormatException e){ + // Valid double not entered - dialog box recalled + } + } + } + } + return c; + } + + // Reads a Complex from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed - String default + public static final synchronized Complex readComplex(String mess, String dflt){ + String line=""; + Complex c = new Complex(); + boolean finish = false; + String mess0 = "Input type: Complex (x + jy)\n"; + String dfltmess = dflt; + mess = mess + "\n"; + + System.out.flush(); + + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + c = Complex.parseComplex(dflt); + finish=true; + line=null; + } + else{ + try{ + c = Complex.parseComplex(line); + finish=true; + }catch(NumberFormatException e){ + // Valid double not entered - dialog box recalled + } + } + } + } + return c; + } + + // Reads a Complex from the dialog box + // No prompt message, No default option + public static final synchronized Complex readComplex(){ + String line=""; + String mess="Input type: Complex (x + jy)"; + Complex c = new Complex(); + boolean finish = false; + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess); + if(line!=null){ + try{ + c = Complex.parseComplex(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid double not entered - dialog box recalled + } + } + } + return c; + } + + // Read a Phasor from dialog box with a prompt message + // accepts strings 'magnitude'<'phase', 'magnitude'<'phase'deg, 'magnitude'<'phase'rad + // e.g. 1.23<34.1deg, -0.67<-56.7, 6.8e2<-0.22rad + // No default option + public static final synchronized Phasor readPhasor(String mess){ + String line=""; + Phasor ph = new Phasor(); + boolean finish = false; + String mess0 = "Input type: Phasor ('mag'<'phase'deg or 'mag'<'phase'rad)\n"; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess); + if(line!=null){ + try{ + ph = Phasor.parsePhasor(line); + finish=true; + }catch(NumberFormatException e){ + // Valid double not entered - dialog box recalled + } + } + } + return ph; + } + + // Reads a Phasor from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed - Phasor default + public static final synchronized Phasor readPhasor(String mess, Phasor dflt){ + String line=""; + Phasor ph = new Phasor(); + boolean finish = false; + String mess0 = "Input type: Phasor ('mag'<'phase'deg or 'mag'<'phase'rad)\n"; + String dfltmess = dflt+""; + mess = mess + "\n"; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + ph = dflt; + finish=true; + line=null; + } + else{ + try{ + ph = Phasor.parsePhasor(line); + finish=true; + }catch(NumberFormatException e){ + // Valid double not entered - dialog box recalled + } + } + } + } + return ph; + } + + // Reads a Phasor from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed - String default + public static final synchronized Phasor readPhasor(String mess, String dflt){ + String line=""; + Phasor ph = new Phasor(); + boolean finish = false; + String mess0 = "Input type: Phasor ('mag'<'phase'deg or 'mag'<'phase'rad)\n"; + String dfltmess = dflt; + mess = mess + "\n"; + + System.out.flush(); + + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + ph = Phasor.parsePhasor(dflt); + finish=true; + line=null; + } + else{ + try{ + ph = Phasor.parsePhasor(line); + finish=true; + }catch(NumberFormatException e){ + // Valid double not entered - dialog box recalled + } + } + } + } + return ph; + } + + // Reads a Phasor from the dialog box + // No prompt message, No default option + public static final synchronized Phasor readPhasor(){ + String line=""; + String mess="Input type: Phasor ('mag'<'phase'deg or 'mag'<'phase'rad)"; + Phasor ph = new Phasor(); + boolean finish = false; + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess); + if(line!=null){ + try{ + ph = Phasor.parsePhasor(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid double not entered - dialog box recalled + } + } + } + return ph; + } + + + + // Reads a float from a dialog box with a prompt message + // No default option + public static final synchronized float readFloat(String mess){ + String line=""; + float d=0.0F; + boolean finish = false; + System.out.flush(); + String mess0 = "Input type: float\n"; + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess); + if(line!=null){ + try{ + d = Float.parseFloat(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid float not entered - dialog box recalled + } + } + } + return d; + } + + // Reads a float from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed + public static final synchronized float readFloat(String mess, float dflt){ + String line=""; + float d=0.0F; + boolean finish = false; + System.out.flush(); + String mess0 = "Input type: float\n"; + mess = mess +"\n"; + String dfltmess = dflt + ""; + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + d=dflt; + finish=true; + line=null; + } + else{ + try{ + d = Float.parseFloat(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid float not entered - dialog box recalled + } + } + } + } + return d; + } + + // Reads a float from the dialog box + // No prompt message, No default option + public static final synchronized float readFloat(){ + String line=""; + String mess="Input type: float"; + float d=0.0F; + boolean finish = false; + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess); + if(line!=null){ + try{ + d = Float.parseFloat(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid float not entered - dialog box recalled + } + } + } + return d; + } + + + + // Reads a int from a dialog box with a prompt message + // No default option + public static final synchronized int readInt(String mess){ + String line=""; + int d=0; + boolean finish = false; + System.out.flush(); + String mess0 = "Input type: int\n"; + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess); + if(line!=null){ + try{ + d = Integer.parseInt(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid int not entered - dialog box recalled + } + } + } + return d; + } + + // Reads a int from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed + public static final synchronized int readInt(String mess, int dflt){ + String line=""; + int d=0; + boolean finish = false; + String mess0 = "Input type: int\n"; + mess = mess +"\n"; + String dfltmess = dflt + ""; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess + " [default value = " + dflt + "] ",dfltmess); + + if(line!=null){ + if(line.equals("")){ + d=dflt; + finish=true; + line=null; + } + else{ + try{ + d = Integer.parseInt(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid int not entered - dialog box recalled + } + } + } + } + return d; + } + + // Reads a int from the dialog box + // No prompt message, No default option + public static final synchronized int readInt(){ + String line=""; + String mess="Input type: int"; + int d=0; + boolean finish = false; + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess); + if(line!=null){ + try{ + d = Integer.parseInt(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid int not entered - dialog box recalled + } + } + } + return d; + } + + + // Reads a long from a dialog box with a prompt message + // No default option + public static final synchronized long readLong(String mess){ + String line=""; + long d=0L; + boolean finish = false; + String mess0 = "Input type: long\n"; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess); + if(line!=null){ + try{ + d = Long.parseLong(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid long not entered - dialog box recalled + } + } + } + return d; + } + + // Reads a long from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed + public static final synchronized long readLong(String mess, long dflt){ + String line=""; + long d=0L; + boolean finish = false; + String mess0 = "Input type: long\n"; + mess = mess +"\n"; + String dfltmess = dflt + ""; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + d=dflt; + finish=true; + line=null; + } + else{ + try{ + d = Long.parseLong(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid long not entered - dialog box recalled + } + } + } + } + return d; + } + + // Reads a long from the dialog box + // No prompt message, No default option + public static final synchronized long readLong(){ + String line=""; + String mess="Input type: long"; + long d=0L; + boolean finish = false; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess); + if(line!=null){ + try{ + d = Long.parseLong(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid long not entered - dialog box recalled + } + } + } + return d; + } + + // Reads a short from a dialog box with a prompt message + // No default option + public static final synchronized long readShort(String mess){ + String line=""; + long d=0; + boolean finish = false; + String mess0 = "Input type: short\n"; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess); + if(line!=null){ + try{ + d = Short.parseShort(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid short not entered - dialog box recalled + } + } + } + return d; + } + + // Reads a short from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed + public static final synchronized short readShort(String mess, short dflt){ + String line=""; + short d=0; + boolean finish = false; + String mess0 = "Input type: short\n"; + mess = mess +"\n"; + String dfltmess = dflt + ""; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + d=dflt; + finish=true; + line=null; + } + else{ + try{ + d = Short.parseShort(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid short not entered - dialog box recalled + } + } + } + } + return d; + } + + // Reads a short from the dialog box + // No prompt message, No default option + public static final synchronized short readShort(){ + String line=""; + String mess="Input type: short"; + short d=0; + boolean finish = false; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess); + if(line!=null){ + try{ + d = Short.parseShort(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid short not entered - dialog box recalled + } + } + } + return d; + } + + // Reads a byte from a dialog box with a prompt message + // No default option + public static final synchronized long readByte(String mess){ + String line=""; + long d=0; + boolean finish = false; + String mess0 = "Input type: short\n"; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess); + if(line!=null){ + try{ + d = Byte.parseByte(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid byte not entered - dialog box recalled + } + } + } + return d; + } + + // Reads a byte from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed + public static final synchronized byte readByte(String mess, byte dflt){ + String line=""; + byte d=0; + boolean finish = false; + String mess0 = "Input type: byte\n"; + mess = mess +"\n"; + String dfltmess = dflt + ""; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + d=dflt; + finish=true; + line=null; + } + else{ + try{ + d = Byte.parseByte(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid byte not entered - dialog box recalled + } + } + } + } + return d; + } + + // Reads a byte from the dialog box + // No prompt message, No default option + public static final synchronized byte readByte(){ + String line=""; + String mess="Input type: byte"; + byte d=0; + boolean finish = false; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess); + if(line!=null){ + try{ + d = Byte.parseByte(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid byte not entered - dialog box recalled + } + } + } + return d; + } + + + // Reads a char from a dialog box with a prompt message + // No default option + public static final synchronized char readChar(String mess){ + String line=""; + char d=' '; + boolean finish = false; + String mess0 = "Input type: char\n"; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess); + if(line!=null){ + if(line.equals("")){ + // Valid char not entered - dialog box recalled + } + else{ + d = line.charAt(0); + finish=true; + } + } + } + return d; + } + + // Reads a char from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed + public static final synchronized char readChar(String mess, char dflt){ + String line=""; + char d = ' '; + boolean finish = false; + String mess0 = "Input type: char\n"; + mess = mess +"\n"; + String dfltmess = dflt + ""; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess + " [default value = " + dflt + "] ", dfltmess); + if(line!=null){ + if(line.equals("")){ + d=dflt; + finish=true; + line=null; + } + else{ + d = line.charAt(0); + finish=true; + } + } + } + return d; + } + + // Reads a char from the dialog box + // No prompt message, No default option + public static final synchronized char readChar(){ + String line=""; + String mess="Input type: char"; + char d=' '; + boolean finish = false; + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess); + if(line!=null){ + if(line.equals("")){ + // Valid char not entered - dialog box recalled + } + else{ + d = line.charAt(0); + finish=true; + } + } + } + return d; + } + + + + + // Reads a line from a dialog box with a prompt message + // No default option + public static final synchronized String readLine(String mess){ + String line=""; + boolean finish = false; + String mess0 = "Input type: String [a line]\n"; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess); + if(line!=null){ + finish=true; + } + } + return line; + } + + // Reads a line from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed + public static final synchronized String readLine(String mess, String dflt){ + String line=""; + boolean finish = false; + String mess0 = "Input type: String [a line]\n"; + mess = mess +"\n"; + String dfltmess = dflt + ""; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess + " [default value = " + dflt + "] ", dfltmess); + if(line!=null){ + if(line.equals("")){ + line=dflt; + finish=true; + } + else{ + finish=true; + } + } + } + return line; + } + + // Reads a line from the dialog box + // No prompt message, No default option + public static final synchronized String readLine(){ + String line=""; + String mess="Input type: String [a line]"; + boolean finish = false; + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess); + if(line!=null){ + finish=true; + } + } + return line; + } + + // Reads a boolean from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed + public static final synchronized boolean readBoolean(String mess, boolean dflt){ + String line=""; + boolean b=false; + boolean finish = false; + System.out.flush(); + String mess0 = "Input boolean\n"; + mess = mess + "\n"; + String dfltmess = dflt+""; + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + b=dflt; + finish=true; + line=null; + } + else{ + if(line.equals("true") || line.trim().equals("TRUE")){ + b=true; + finish=true; + } + else{ + if(line.equals("false") || line.trim().equals("FALSE")){ + b=false; + finish=true; + } + } + } + } + } + return b; + } + + // Reads a boolean from a dialog box with a prompt message + // No default option + public static final synchronized boolean readBoolean(String mess){ + String line=""; + boolean b=false; + boolean finish = false; + System.out.flush(); + String mess0 = "Input type: boolean\n"; + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess); + if(line!=null){ + if(line.equals("true") || line.trim().equals("TRUE")){ + b=true; + finish=true; + } + else{ + if(line.equals("false") || line.trim().equals("FALSE")){ + b=false; + finish=true; + } + } + } + } + return b; + } + + // Reads a boolean from the dialog box + // No prompt message, No default option + public static final synchronized boolean readBoolean(){ + String line=""; + String mess="Input type: boolean"; + boolean b=false; + boolean finish = false; + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess); + if(line!=null){ + if(line.equals("true") || line.trim().equals("TRUE")){ + b=true; + finish=true; + } + else{ + if(line.equals("false") || line.trim().equals("FALSE")){ + b=false; + finish=true; + } + } + } + } + return b; + } + + // Read a BigDecimal from dialog box with a prompt message + // No default option + public static final synchronized BigDecimal readBigDecimal(String mess){ + String line=""; + BigDecimal big = null; + boolean finish = false; + String mess0 = "Input type: BigDecimal\n"; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess); + if(line!=null){ + try{ + big = new BigDecimal(line); + finish=true; + }catch(NumberFormatException e){ + // Valid BigDecimal not entered - dialog box recalled + } + } + } + return big; + } + + // Reads a BigDecimal from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed - BigDecimal default + public static final synchronized BigDecimal readBigDecimal(String mess, BigDecimal dflt){ + String line=""; + BigDecimal big = null; + boolean finish = false; + String mess0 = "Input type: BigDecimal\n"; + String dfltmess = dflt.toString()+""; + mess = mess + "\n"; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + big = dflt; + finish=true; + line=null; + } + else{ + try{ + big = new BigDecimal(line); + finish=true; + }catch(NumberFormatException e){ + // Valid BigDecimal not entered - dialog box recalled + } + } + } + } + return big; + } + + // Reads a BigDecimal from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed - String default + public static final synchronized BigDecimal readBigDecimal(String mess, String dflt){ + String line=""; + BigDecimal big = null; + boolean finish = false; + String mess0 = "Input type: BigDecimal\n"; + String dfltmess = dflt; + mess = mess + "\n"; + + System.out.flush(); + + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + big = new BigDecimal(dflt); + finish=true; + line=null; + } + else{ + try{ + big = new BigDecimal(line); + finish=true; + }catch(NumberFormatException e){ + // Valid BigDecimal not entered - dialog box recalled + } + } + } + } + return big; + } + + // Reads a BigDecimal from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed - double default + public static final synchronized BigDecimal readBigDecimal(String mess, double dflt){ + String line=""; + BigDecimal big = null; + boolean finish = false; + String mess0 = "Input type: BigDecimal\n"; + Double dfltD = new Double(dflt); + String dfltmess = dfltD.toString(); + mess = mess + "\n"; + + System.out.flush(); + + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + big = new BigDecimal(dfltmess); + finish=true; + line=null; + } + else{ + try{ + big = new BigDecimal(line); + finish=true; + }catch(NumberFormatException e){ + // Valid BigDecimal not entered - dialog box recalled + } + } + } + } + return big; + } + + // Reads a BigDecimal from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed - float default + public static final synchronized BigDecimal readBigDecimal(String mess, float dflt){ + String line=""; + BigDecimal big = null; + boolean finish = false; + String mess0 = "Input type: BigDecimal\n"; + Float dfltF = new Float(dflt); + String dfltmess = dfltF.toString(); + mess = mess + "\n"; + + System.out.flush(); + + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + big = new BigDecimal(dfltmess); + finish=true; + line=null; + } + else{ + try{ + big = new BigDecimal(line); + finish=true; + }catch(NumberFormatException e){ + // Valid BigDecimal not entered - dialog box recalled + } + } + } + } + return big; + } + + // Reads a BigDecimal from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed - long default + public static final synchronized BigDecimal readBigDecimal(String mess, long dflt){ + String line=""; + BigDecimal big = null; + boolean finish = false; + String mess0 = "Input type: BigDecimal\n"; + Long dfltF = new Long(dflt); + String dfltmess = dfltF.toString(); + mess = mess + "\n"; + + System.out.flush(); + + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + big = new BigDecimal(dfltmess); + finish=true; + line=null; + } + else{ + try{ + big = new BigDecimal(line); + finish=true; + }catch(NumberFormatException e){ + // Valid BigDecimal not entered - dialog box recalled + } + } + } + } + return big; + } + +// Reads a BigDecimal from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed - int default + public static final synchronized BigDecimal readBigDecimal(String mess, int dflt){ + String line=""; + BigDecimal big = null; + boolean finish = false; + String mess0 = "Input type: BigDecimal\n"; + Integer dfltF = new Integer(dflt); + String dfltmess = dfltF.toString(); + mess = mess + "\n"; + + System.out.flush(); + + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + big = new BigDecimal(dfltmess); + finish=true; + line=null; + } + else{ + try{ + big = new BigDecimal(line); + finish=true; + }catch(NumberFormatException e){ + // Valid BigDecimal not entered - dialog box recalled + } + } + } + } + return big; + } + + // Reads a BigDecimal from the dialog box + // No prompt message, No default option + public static final synchronized BigDecimal readBigDecimal(){ + String line=""; + String mess="Input type: BigDecimal"; + BigDecimal big = null; + boolean finish = false; + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess); + if(line!=null){ + try{ + big = new BigDecimal(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid BigDecimal not entered - dialog box recalled + } + } + } + return big; + } + + // Read a BigInteger from dialog box with a prompt message + // No default option + public static final synchronized BigInteger readBigInteger(String mess){ + String line=""; + BigInteger big = null; + boolean finish = false; + String mess0 = "Input type: BigInteger\n"; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0+mess); + if(line!=null){ + try{ + big = new BigInteger(line); + finish=true; + }catch(NumberFormatException e){ + // Valid BigInteger not entered - dialog box recalled + } + } + } + return big; + } + + // Reads a BigInteger from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed - BigInteger default + public static final synchronized BigInteger readBigInteger(String mess, BigInteger dflt){ + String line=""; + BigInteger big = null; + boolean finish = false; + String mess0 = "Input type: BigInteger\n"; + String dfltmess = dflt.toString()+""; + mess = mess + "\n"; + + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + big = dflt; + finish=true; + line=null; + } + else{ + try{ + big = new BigInteger(line); + finish=true; + }catch(NumberFormatException e){ + // Valid BigInteger not entered - dialog box recalled + } + } + } + } + return big; + } + + // Reads a BigInteger from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed - String default + public static final synchronized BigInteger readBigInteger(String mess, String dflt){ + String line=""; + BigInteger big = null; + boolean finish = false; + String mess0 = "Input type: BigInteger\n"; + String dfltmess = dflt; + mess = mess + "\n"; + + System.out.flush(); + + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + big = new BigInteger(dflt); + finish=true; + line=null; + } + else{ + try{ + big = new BigInteger(line); + finish=true; + }catch(NumberFormatException e){ + // Valid BigInteger not entered - dialog box recalled + } + } + } + } + return big; + } + + // Reads a BigInteger from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed - long default + public static final synchronized BigInteger readBigInteger(String mess, long dflt){ + String line=""; + BigInteger big = null; + boolean finish = false; + String mess0 = "Input type: BigInteger\n"; + Long dfltF = new Long(dflt); + String dfltmess = dfltF.toString(); + mess = mess + "\n"; + + System.out.flush(); + + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + big = new BigInteger(dfltmess); + finish=true; + line=null; + } + else{ + try{ + big = new BigInteger(line); + finish=true; + }catch(NumberFormatException e){ + // Valid BigInteger not entered - dialog box recalled + } + } + } + } + return big; + } + + // Reads a BigInteger from a dialog box with a prompt message and the return + // of a default option if the return key alone is pressed - int default + public static final synchronized BigInteger readBigInteger(String mess, int dflt){ + String line=""; + BigInteger big = null; + boolean finish = false; + String mess0 = "Input type: BigInteger\n"; + Integer dfltF = new Integer(dflt); + String dfltmess = dfltF.toString(); + mess = mess + "\n"; + + System.out.flush(); + + + while(!finish){ + line = JOptionPane.showInputDialog(mess0 + mess + " [default value = " + dflt + "] ", dfltmess); + + if(line!=null){ + if(line.equals("")){ + big = new BigInteger(dfltmess); + finish=true; + line=null; + } + else{ + try{ + big = new BigInteger(line); + finish=true; + }catch(NumberFormatException e){ + // Valid BigInteger not entered - dialog box recalled + } + } + } + } + return big; + } + + // Reads a BigInteger from the dialog box + // No prompt message, No default option + public static final synchronized BigInteger readBigInteger(){ + String line=""; + String mess="Input type: BigInteger"; + BigInteger big = null; + boolean finish = false; + System.out.flush(); + + while(!finish){ + line = JOptionPane.showInputDialog(mess); + if(line!=null){ + try{ + big = new BigInteger(line.trim()); + finish=true; + }catch(NumberFormatException e){ + // Valid BigInteger not entered - dialog box recalled + } + } + } + return big; + } + + // returns true if answer is yes, false if not, default = YES + public static final synchronized boolean yesNo(String question){ + int ans = JOptionPane.showConfirmDialog(null, question, "Db Class Yes or No Box", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + boolean ansb =false; + if(ans == 0)ansb =true; + return ansb; + } + + // returns true if answer is yes, false if not, default = NO + public static final synchronized boolean noYes(String question){ + Object[] opts = {"Yes", "No"}; + int ans = JOptionPane.showOptionDialog(null, question, "Db Class Yes or No Box", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, opts, opts[1]); + boolean ansb =false; + if(ans == 0)ansb =true; + return ansb; + } + + + // Shows a message and the value of a double in a message dialogue box + public static final synchronized void show(String message, double output){ + JOptionPane.showMessageDialog(null, message+" "+output, "Db.show (double)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a truncated double in a message dialogue box + public static final synchronized void show(String message, double output, int trunc){ + JOptionPane.showMessageDialog(null, message+" "+Fmath.truncate(output, trunc), "Db.show (double)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a float in a message dialogue box + public static final synchronized void show(String message, float output){ + JOptionPane.showMessageDialog(null, message+" "+output, "Db.show (float)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a truncated float in a message dialogue box + public static final synchronized void show(String message, float output, int trunc){ + JOptionPane.showMessageDialog(null, message+" "+Fmath.truncate(output, trunc), "Db.show (float)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a BigDecimal in a message dialogue box + public static final synchronized void show(String message, BigDecimal output){ + JOptionPane.showMessageDialog(null, message+" "+output.toString(), "Db.show (BigDecimal)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a BigInteger in a message dialogue box + public static final synchronized void show(String message, BigInteger output){ + JOptionPane.showMessageDialog(null, message+" "+output.toString(), "Db.show (BigInteger)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a int in a message dialogue box + public static final synchronized void show(String message, int output){ + JOptionPane.showMessageDialog(null, message+" "+output, "Db.show (int)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a long in a message dialogue box + public static final synchronized void show(String message, long output){ + JOptionPane.showMessageDialog(null, message+" "+output, "Db.show (long)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a short in a message dialogue box + public static final synchronized void show(String message, short output){ + JOptionPane.showMessageDialog(null, message+" "+output, "Db.show (short)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a byte in a message dialogue box + public static final synchronized void show(String message, byte output){ + JOptionPane.showMessageDialog(null, message+" "+output, "Db.show (byte)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a Complex in a message dialogue box + public static final synchronized void show(String message, Complex output){ + JOptionPane.showMessageDialog(null, message+" "+output, "Db.show (Complex)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a truncated Complex in a message dialogue box + public static final synchronized void show(String message, Complex output, int trunc){ + JOptionPane.showMessageDialog(null, message+" "+Complex.truncate(output, trunc), "Db.show (Complex)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a Phasor in a message dialogue box + public static final synchronized void show(String message, Phasor output){ + JOptionPane.showMessageDialog(null, message+" "+output, "Db.show (Phasor)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a truncated Phasor in a message dialogue box + public static final synchronized void show(String message, Phasor output, int trunc){ + JOptionPane.showMessageDialog(null, message+" "+Phasor.truncate(output, trunc), "Db.show (Phasor)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a ErrorProp in a message dialogue box + public static final synchronized void show(String message, ErrorProp output){ + JOptionPane.showMessageDialog(null, message+" "+output, "Db.show (ErrorProp)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a ErrorProp in a message dialogue box + public static final synchronized void show(String message, ErrorProp output, int trunc){ + JOptionPane.showMessageDialog(null, message+" "+ErrorProp.truncate(output, trunc), "Db.show (ErrorProp)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a ComplexErrorProp in a message dialogue box + public static final synchronized void show(String message, ComplexErrorProp output){ + JOptionPane.showMessageDialog(null, message+" "+output, "Db.show (ComplexErrorProp)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a truncated ComplexErrorProp in a message dialogue box + public static final synchronized void show(String message, ComplexErrorProp output, int trunc){ + JOptionPane.showMessageDialog(null, message+" "+ComplexErrorProp.truncate(output, trunc), "Db.show (ComplexErrorProp)", JOptionPane.INFORMATION_MESSAGE); + } + // Shows a message and the value of a boolean in a message dialogue box + public static final synchronized void show(String message, boolean output){ + JOptionPane.showMessageDialog(null, message+" "+output, "Db.show (boolean)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a char in a message dialogue box + public static final synchronized void show(String message, char output){ + JOptionPane.showMessageDialog(null, message+" "+output, "Db.show (char)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message and the value of a String in a message dialogue box + public static final synchronized void show(String message, String output){ + JOptionPane.showMessageDialog(null, message+" "+output, "Db.show (String)", JOptionPane.INFORMATION_MESSAGE); + } + + // Shows a message only in a message dialogue box + public static final synchronized void show(String message){ + JOptionPane.showMessageDialog(null, message, "Db.show (message only)", JOptionPane.INFORMATION_MESSAGE); + } + + // Multiple choice box - Multiple query column closely matching box row + public static final synchronized int optionBox(String headerComment, String[] comments, String[] boxTitles, int defaultBox){ + int nChoice = boxTitles.length; + if(nChoice!=comments.length)throw new IllegalArgumentException("There must be the same number of boxTitles and comments"); + Object[] options = new Object[nChoice]; + for(int i=0; i<nChoice; i++){ + options[i] = "(" + (i+1) +") " + boxTitles[i]; + } + String quest = "1. " + comments[0] + "\n"; + for(int i=1; i<nChoice; i++){ + quest = quest + (i+1) +". " + comments[i] + "\n"; + } + + return 1 + JOptionPane.showOptionDialog(null, quest, headerComment, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,null, options, options[defaultBox-1]); + } + + // Multiple choice box - Single general query + public static final synchronized int optionBox(String headerComment, String quest, String[] boxTitles, int defaultBox){ + int nChoice = boxTitles.length; + Object[] options = new Object[nChoice]; + for(int i=0; i<nChoice; i++){ + options[i] = "(" + (i+1) +") " + boxTitles[i]; + } + + return 1 + JOptionPane.showOptionDialog(null, quest, headerComment, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,null, options, options[defaultBox-1]); + } + + // Displays dialogue box asking if you wish to exit program + // Answering yes end program + public static final synchronized void endProgram(){ + + int ans = JOptionPane.showConfirmDialog(null, "Do you wish to end the program", "End Program", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if(ans==0){ + System.exit(0); + } + else{ + JOptionPane.showMessageDialog(null, "Now you must press the appropriate escape key/s, e.g. Ctrl C, to exit this program"); + } + } +} + diff --git a/src/main/java/flanagan/io/DigiGraph.java b/src/main/java/flanagan/io/DigiGraph.java new file mode 100755 index 0000000000000000000000000000000000000000..c0c3f6d813a0f1051c962be206744d7fe78513c0 --- /dev/null +++ b/src/main/java/flanagan/io/DigiGraph.java @@ -0,0 +1,816 @@ +/* +* Class DigiGraph +* +* Class to digitize a graph presented as a gif, jpg or png +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: September 2006 +* UPDATE: 8 October 2006, 2 November 2006, 12 May 2008, 5 July 2008, 3 December 2008 +* +* DOCUMENTATION: +* See Michael T Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* http://www.ee.ucl.ac.uk/~mflanaga/java/DigiGraph.html +* +* Copyright (c) 2006 - 2008 +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, +* this list of conditions and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission +* from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +*****************************************************************************************************************************************************/ + +package flanagan.io; + +import java.awt.*; +import java.awt.image.*; +import java.awt.event.*; +import java.util.ArrayList; +import java.io.*; +import java.net.*; +import javax.swing.*; +import javax.swing.JFrame; + +import flanagan.io.*; +import flanagan.interpolation.CubicSpline; +import flanagan.math.Fmath; +import flanagan.plot.PlotGraph; + +public class DigiGraph extends Canvas implements MouseListener{ + + private Image pic = null; // image containing graph to be digitised + private String imagePath = null; // path, i.e. address\name, of the .png, .gif or .jpg containing graph + private String imageName = null; // name of the .gif, .png or .jpg file containing graph + private String extension = null; // extension of file name, e.g. gif, png or jpg + + private String outputFile = null; // output file (containing digitisation values) name + private FileOutput fout = null; // output file (containing digitisation values) reference + private int trunc = 16; // number of decimal places in output data + + private String path = "C:"; // path for file selection window + private int windowWidth = 0; // width of the window for the graph in pixels + private int windowHeight = 0; // height of the window for the graph in pixels + private int closeChoice = 1; // =1 clicking on close icon causes window to close + // and the the program is exited. + // =2 clicking on close icon causes window to close + // leaving the program running. + + private int xPos = 0; // mouse x-axis position (in pixels)on last click + private int yPos = 0; // mouse y-axis position (in pixels)on last click + private int button = 0; // mouse button last clicked + // = 0; no button clicked + // = 1; left mouse button last clicked + // (= 2; middle mouse button last clicked) + // = 3; right mouse button last clicked + private int sumX = 0; // sum of xPos in calculation of a calibration point + private int sumY = 0; // sum of yPos in calculation of a calibration point + private int iSum = 0; // number of xPos and yPos in calculation of a calibration point + private boolean mouseEntered = false; // = true when mouse enters object + // = false when mouse leaves object + private double lowYvalue = 0.0; // Y-axis value (entered as double) of the clicked low Y-axis value + private double lowYaxisXpixel = 0.0; // X-axis pixel number of the clicked known low Y-axis value + private double lowYaxisYpixel = 0.0; // Y-axis pixel number of the clicked known low Y-axis value + private double highYvalue = 0.0; // Y-axis value (entered as double) of the clicked high Y-axis value + private double highYaxisXpixel = 0.0; // X-axis pixel number of the clicked known high Y-axis value + private double highYaxisYpixel = 0.0; // Y-axis pixel number of the clicked known high Y-axis value + private double lowXvalue = 0.0; // X-axis value (entered as double) of the clicked low X-axis value + private double lowXaxisXpixel = 0.0; // X-axis pixel number of the clicked known low X-axis value + private double lowXaxisYpixel = 0.0; // Y-axis pixel number of the clicked known low X-axis value + private double highXvalue = 0.0; // X-axis value (entered as double) of the clicked high X-axis value + private double highXaxisXpixel = 0.0; // X-axis pixel number of the clicked known high X-axis value + private double highXaxisYpixel = 0.0; // Y-axis pixel number of the clicked known high X-axis value + + private ArrayList<Integer> xAndYvalues = new ArrayList<Integer>(); + // ArrayList holding clicked point xPos and yPos values + private int iCounter = 0; // counter for clicks or sum of clicks on first for calibration points + private double angleXaxis = 0.0; // clockwise angle from normal of x-axis (degrees) + private double angleYaxis = 0.0; // clockwise angle from normal of y-axis (degrees) + private double angleMean = 0.0; // mean clockwise angle of axes from normal (degrees) + private double angleTolerance = 0.0; // tolerance in above angle before a rotation of all points performed + // default option is to rotate if angle is not zero + private boolean rotationDone = false; // = false: no rotation of points performed + // = true: all points have been rotated + + private double[] xPosPixel = null; // x pixel values converted to double + private double[] yPosPixel = null; // y pixel values converted to double + private double[] xPositions = null; // Digitized and scaled x values + private double[] yPositions = null; // Digitized and scaled y values + private int nData = 0; // Number of points digitized (excluding calibration points) + + private int nInterpPoints = 0; // Nnumber of interpolation points + private boolean interpOpt = false; // = true if interpolation requested + private double[] xInterp = null; // Interpolated x values + private double[] yInterp = null; // Interpolated y values + private boolean plotOpt = true; // = false if plot of interpolated data not required + + private boolean noIdentical = true; // = true - all identical points stripped to one instance of the identical points + // = false - all identical points retained + + private int imageFormat = 0; // = 0 no image file loaded + // = 1 GIF format + // = 2 JPEG format + // = 3 PNG format + + private boolean digitizationDone = false; // = true when digitization complete + + private boolean noYlow = true; // = false when lower y-axis calibration point has been entered + private boolean noXlow = true; // = false when lower x-axis calibration point has been entered + private boolean noYhigh = true; // = false when higher y-axis calibration point has been entered + private boolean noXhigh = true; // = false when higher x-axis calibration point has been entered + + private boolean resize = false; // = true if image is resized + + // Create the window object + private JFrame window = new JFrame("Michael T Flanagan's digitizing program - DigiGraph"); + + // Constructors + // image to be selected from a file select window + // window opens on default setting + public DigiGraph(){ + super(); + + // Set graph digitizing window size + setWindowSize(); + + // select image + selectImage(); + + // set image + setImage(); + + // Name outputfile + outputFileChoice(); + + // Add the MouseListener + addMouseListener(this); + } + + // image to be selected from a file select window + // window opens on path (windowPath) provided + public DigiGraph(String windowPath){ + super(); + + // Set graph digitizing window size + setWindowSize(); + + // Set window path + this.path = windowPath; + + // select image + selectImage(); + + // set image + setImage(); + + // Name outputfile + outputFileChoice(); + + // Add the MouseListener + addMouseListener(this); + } + + // Set graph digitizing window size + private void setWindowSize(){ + + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); // get computer screen size + this.windowWidth = screenSize.width - 30; // width of the window for the graph in pixels + this.windowHeight = screenSize.height - 40; // height of the window for the graph in pixels + } + + // Select graph image + private void selectImage(){ + + // Identify computer + String computerName = null; + try{ + InetAddress localaddress = InetAddress.getLocalHost(); + computerName = localaddress.getHostName(); + } + catch(UnknownHostException e){ + System.err.println("Cannot detect local host : " + e); + } + + // Set path to file selection window + // Replace "name" by your "computer's name" and C:\\DigiGraphDirectory by the path to the directory containing the image to be digitized + // Default path is to the C:\ directory or system default directory if no C drive present + if(computerName.equals("name"))this.path = "C:\\DigiGraphDirectory"; + + // select image file + FileChooser fc = new FileChooser(this.path); + this.imageName = fc.selectFile(); + if(!fc.fileFound()){ + System.out.println("Class DigiGraph: No successful selection of an image file occurred"); + System.exit(0); + } + this.imagePath = fc.getPathName(); + + int lastDot = this.imagePath.lastIndexOf('.'); + this.extension = this.imagePath.substring(lastDot+1); + if(this.extension.equalsIgnoreCase("gif"))imageFormat=1; + if(this.extension.equalsIgnoreCase("jpg"))imageFormat=2; + if(this.extension.equalsIgnoreCase("jpeg"))imageFormat=2; + if(this.extension.equalsIgnoreCase("jpe"))imageFormat=2; + if(this.extension.equalsIgnoreCase("jfif"))imageFormat=2; + if(this.extension.equalsIgnoreCase("png"))imageFormat=3; + } + + // Set graph image + private void setImage(){ + this.pic = Toolkit.getDefaultToolkit().getImage(this.imagePath); + } + + // Name outputfile and set number of decimal placess in the output data + private void outputFileChoice(){ + int posdot = this.imagePath.lastIndexOf('.'); + this.outputFile = this.imagePath.substring(0, posdot) + "_digitized.txt"; + this.outputFile = Db.readLine("Enter output file name ", this.outputFile); + this.fout = new FileOutput(this.outputFile); + this.trunc = Db.readInt("Enter number of decimal places required in output data ", this.trunc); + } + + // Reset the number of decimal places in the output data + public void setTruncation(int trunc){ + this.trunc = trunc; + } + + // Reset tolerance in axis rotation before applying rotation (degrees) + public void setRotationTolerance(double tol){ + this.angleTolerance = tol; + } + + // Reset option of plotting the data + // Prevents a plot of the digitized data and the interpolated data, if interpolation optiion chosen, + // from being displayed + public void noPlot(){ + this.plotOpt = false;; + } + + // Reset path for selection window + public void setPath(String path){ + this.path = path; + } + + // Reset height of graph window (pixels) + public void setWindowHeight(int windowHeight){ + this.windowHeight = windowHeight; + } + + // Reset width of graph window (pixels) + public void setWindowWidth(int windowWidth){ + this.windowWidth = windowWidth; + } + + // Reset close choice + public void setCloseChoice(int choice){ + this.closeChoice = choice; + } + + // Reset stripping of identical points option + // Keep all identical points + public void keepIdenticalPoints(){ + this.noIdentical = false; + } + + // The paint method to display the graph. + public void paint(Graphics g){ + + // Call graphing method + graph(g); + } + + // Set up the window, show graph and digitize + public void digitize(){ + + // Set the initial size of the graph window + this.window.setSize(this.windowWidth, this.windowHeight); + + // Set background colour + this.window.getContentPane().setBackground(Color.white); + + // Choose close box + if(this.closeChoice==1){ + this.window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + else{ + this.window.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + } + + // Add graph canvas + this.window.getContentPane().add("Center", this); + + // Set the window up + this.window.pack(); + this.window.setResizable(true); + this.window.toFront(); + + // Show the window + this.window.setVisible(true); + } + + + // Set up the window, show graph and digitize (alternate spelling) + public void digitise(){ + this.digitize(); + } + + + // Display graph and get coordinates + private void graph(Graphics g){ + + // Display graph to be digitized + g.drawImage(this.pic, 10, 30, this); + if(!this.resize){ + g.drawString("RIGHT click anywhere on the screen", 5, 10); + int width = this.pic.getWidth(null); + int height = this.pic.getHeight(null); + System.out.println(width + " xxx " + height); + g.drawString(" ", 5, 10); + double factor = (double)(windowHeight-30)/(double)height; + if((int)(width*factor)>(windowWidth-10))factor = (double)(windowWidth-10)/(double)width; + height = (int)((height-30)*factor*0.95); + width = (int)((width-10)*factor+0.95); + this.pic = this.pic.getScaledInstance(width, height, Image.SCALE_DEFAULT); + g.drawImage(this.pic, 10, 30, this); + this.resize=true; + } + + // Displays cross at pixel coordinates clicked + boolean test=true; + if(this.xPos==0 && this.yPos==0)test=false; + if(test)cursorDoneSign(g, xPos, yPos); + + // Shows action required at top left of window + // and opens dialog box to input calibration points + if(!this.digitizationDone){ + switch(this.iCounter){ + case 0: g.drawString("RIGHT click on lower Y-axis calibration point", 5, 10); + break; + case 1: if(this.noYlow){ + this.lowYvalue = Db.readDouble("Enter lower Y-axis calibration value"); + this.noYlow = false; + } + g.drawString("RIGHT click on higher Y-axis calibration point", 5, 10); + break; + case 2: if(this.noYhigh){ + this.highYvalue = Db.readDouble("Enter higher Y-axis calibration value"); + this.noYhigh = false; + } + g.drawString("RIGHT click on lower X-axis calibration point", 5, 10); + break; + case 3: if(this.noXlow){ + this.lowXvalue = Db.readDouble("Enter lower X-axis calibration value"); + this.noXlow = false; + } + g.drawString("RIGHT click on higher X-axis calibration point", 5, 10); + break; + case 4: if(this.noXhigh){ + this.highXvalue = Db.readDouble("Enter higher X-axis calibration value"); + this.noXhigh = false; + } + g.drawString("LEFT click on points to be digitized [right click when finished digitizing]", 5, 10); + break; + default:g.drawString("LEFT click on points to be digitized [right click when finished digitizing]", 5, 10); + } + } + else{ + g.drawString("You may now close this window", 5, 10); + } + } + + private void cursorDoneSign(Graphics g, int x, int y){ + g.drawLine(x-5, y, x+5, y); + g.drawLine(x, y-5, x, y+5); + g.fillOval(x-3, y-3, 7, 7); + } + + // This method will be called when the mouse has been clicked. + public void mouseClicked(MouseEvent me) { + + if(!this.digitizationDone){ + switch(this.iCounter){ + // Low y-axis calibration point + case 0: this.xPos = me.getX(); + this.yPos = me.getY(); + + // identify left (1) or right (3) hand mouse click + this.button = me.getButton(); + // add to sum + if(this.button==1){ + this.sumX += this.xPos; + this.sumY += this.yPos; + this.iSum++; + } + else if(this.button==3){ + this.sumX += this.xPos; + this.sumY += this.yPos; + this.iSum++; + this.lowYaxisXpixel = (double)this.sumX/(double)this.iSum; + this.lowYaxisYpixel = (double)this.windowHeight - (double)this.sumY/(double)this.iSum; + this.iCounter++; + this.sumX = 0; + this.sumY = 0; + this.iSum = 0; + } + + break; + // High y-axis calibration point + case 1: this.xPos = me.getX(); + this.yPos = me.getY(); + + // identify left (1) or right (3) hand mouse click + this.button = me.getButton(); + // add to sum + if(this.button==1){ + this.sumX += this.xPos; + this.sumY += this.yPos; + this.iSum++; + } + else if(this.button==3){ + this.sumX += this.xPos; + this.sumY += this.yPos; + this.iSum++; + this.highYaxisXpixel = (double)this.sumX/(double)this.iSum; + this.highYaxisYpixel = (double)this.windowHeight - (double)this.sumY/(double)this.iSum; + this.iCounter++; + this.sumX = 0; + this.sumY = 0; + this.iSum = 0; + } + break; + // Low x-axis calibration point + case 2: this.xPos = me.getX(); + this.yPos = me.getY(); + + // identify left (1) or right (3) hand mouse click + this.button = me.getButton(); + // add to sum + if(this.button==1){ + this.sumX += this.xPos; + this.sumY += this.yPos; + this.iSum++; + } + else if(this.button==3){ + this.sumX += this.xPos; + this.sumY += this.yPos; + this.iSum++; + this.lowXaxisXpixel = (double)this.sumX/(double)this.iSum; + this.lowXaxisYpixel = (double)this.windowHeight - (double)this.sumY/(double)this.iSum; + this.iCounter++; + this.sumX = 0; + this.sumY = 0; + this.iSum = 0; + } + break; + // High x-axis calibration point + case 3: this.xPos = me.getX(); + this.yPos = me.getY(); + + // identify left (1) or right (3) hand mouse click + this.button = me.getButton(); + // add to sum + + PixelGrabber pixelGrabber=new PixelGrabber(pic, this.xPos, this.yPos, 1, 1, false); + + if(this.button==1){ + this.sumX += this.xPos; + this.sumY += this.yPos; + this.iSum++; + } + else if(this.button==3){ + this.sumX += this.xPos; + this.sumY += this.yPos; + this.iSum++; + this.highXaxisXpixel = (double)this.sumX/(double)this.iSum; + this.highXaxisYpixel = (double)this.windowHeight - (double)this.sumY/(double)this.iSum; + this.iCounter++; + this.sumX = 0; + this.sumY = 0; + this.iSum = 0; + } + break; + // Data points + default: + this.xPos = me.getX(); + this.yPos = me.getY(); + + // identify left (1) or right (3) hand mouse click + this.button = me.getButton(); + if(this.button==1){ + this.xAndYvalues.add(new Integer(this.xPos)); + this.xAndYvalues.add(new Integer(this.yPos)); + } + + // close file if right button clicked + if(this.button==3 && this.xAndYvalues.size()/2!=0){ + this.outputData(); + this.digitizationDone = true; + } + } + } + + //show the results of the click + repaint(); + } + + // Output data to file and to graph + private void outputData(){ + + // dimension arrays + this.nData = this.xAndYvalues.size()/2; + System.out.println("nData " + this.nData); + this.xPositions = new double[this.nData]; + this.yPositions = new double[this.nData]; + this.xPosPixel = new double[this.nData]; + this.yPosPixel = new double[this.nData]; + + int ii = 0; + // Convert pixel values to doubles + for(int i=0; i<this.nData; i++){ + int xx = this.xAndYvalues.get(ii); + ii++; + int yy = this.xAndYvalues.get(ii); + ii++; + this.xPosPixel[i] = (double)xx; + this.yPosPixel[i] = (double)this.windowHeight - (double)yy; + } + + // Check if graph axes are to be rotated and, if so, rotate + this.checkForRotation(); + + // Scale the pixel values to true values + for(int i=0; i<this.nData; i++){ + this.xPositions[i] = this.lowXvalue + (this.xPosPixel[i] - this.lowXaxisXpixel)*(this.highXvalue - this.lowXvalue)/(this.highXaxisXpixel - this.lowXaxisXpixel); + this.yPositions[i] = this.lowYvalue + (this.yPosPixel[i] - this.lowYaxisYpixel)*(this.highYvalue - this.lowYvalue)/(this.highYaxisYpixel - this.lowYaxisYpixel); + } + + // Check for identical points and remove one of all pairs of such points + if(this.noIdentical)this.checkForIdenticalPoints(); + + // Request to increase number of data points using a cubic spline interpolation + String message = "Do you wish to increase number of data points\n"; + message += "using cubic spline interpolation?"; + boolean opt = Db.noYes(message); + if(opt){ + this.nInterpPoints = Db.readInt("Enter number of interpolation points", 200); + interpolation(); + this.interpOpt = true; + } + else{ + if(plotOpt)plotDigitisedPoints(); + } + + // Output digitized data + this.fout.println("Digitization output for DigiGraph class (M. T. Flanagan Java Library)"); + this.fout.println(); + this.fout.dateAndTimeln(); + this.fout.println(); + this.fout.println("Image used in the digitization: " + this.imageName); + this.fout.println("Location of the image used in the digitization: " + this.imagePath); + this.fout.println(); + this.fout.println("X-axis skew angle " + Fmath.truncate(this.angleXaxis, 4) + " degrees"); + this.fout.println("Y-axis skew angle " + Fmath.truncate(this.angleYaxis, 4) + " degrees"); + this.fout.println("Axes mean skew angle " + Fmath.truncate(this.angleMean, 4) + " degrees"); + if(this.rotationDone){ + this.fout.println("Axes and all points rotated to bring axes to normal position"); + } + else{ + this.fout.println("No rotation of axes or points performed"); + } + this.fout.println(); + this.fout.println("Number of digitized points: " + this.nData); + this.fout.println(); + this.fout.printtab("X-value"); + this.fout.println("Y-value"); + + for(int i=0; i<this.nData; i++){ + this.fout.printtab(Fmath.truncate(this.xPositions[i], trunc)); + this.fout.println(Fmath.truncate(this.yPositions[i], trunc)); + } + this.fout.println(); + + // Output interpolated data if calculated + if(this.interpOpt){ + this.fout.println(); + this.fout.println("Interpolated data (cubic spline)"); + this.fout.println(); + this.fout.println("Number of interpolated points: " + this.nInterpPoints); + this.fout.println(); + this.fout.printtab("X-value"); + this.fout.println("Y-value"); + for(int i=0; i<this.nInterpPoints; i++){ + this.fout.printtab(Fmath.truncate(this.xInterp[i], trunc)); + this.fout.println(Fmath.truncate(this.yInterp[i], trunc)); + } + } + + this.fout.close(); + } + + // Check for axes rotation + private void checkForRotation(){ + double tangent = (this.highYaxisXpixel - this.lowYaxisXpixel)/(this.highYaxisYpixel - this.lowYaxisYpixel); + this.angleYaxis = Math.toDegrees(Math.atan(tangent)); + tangent = (this.lowXaxisYpixel - this.highXaxisYpixel)/(this.highXaxisXpixel - this.lowXaxisXpixel); + this.angleXaxis = Math.toDegrees(Math.atan(tangent)); + this.angleMean = (this.angleXaxis + this.angleYaxis)/2.0; + double absMean = Math.abs(this.angleMean); + if(absMean!=0.0 && absMean>this.angleTolerance)performRotation(); + } + + // Rotate axes and all points + private void performRotation(){ + // Find pixel zero-zero origin + double tangentX = (this.highXaxisYpixel - this.lowXaxisYpixel)/(this.highXaxisXpixel - this.lowXaxisXpixel); + double interceptX = this.highXaxisYpixel - tangentX*this.highXaxisXpixel; + double tangentY = (this.highYaxisYpixel - this.lowYaxisYpixel)/(this.highYaxisXpixel - this.lowYaxisXpixel); + double interceptY = this.highYaxisYpixel - tangentY*this.highYaxisXpixel; + double originX = (interceptX - interceptY)/(tangentY - tangentX); + double originY = tangentY*originX + interceptY; + + // Rotate axes calibration points + double angleMeanRad = Math.toRadians(this.angleMean); + double cosphi = Math.cos(-angleMeanRad); + double sinphi = Math.sin(-angleMeanRad); + double highXaxisXpixelR = (this.highXaxisXpixel-originX)*cosphi + (this.highXaxisYpixel-originY)*sinphi + originX; + double highXaxisYpixelR = -(this.highXaxisXpixel-originX)*sinphi + (this.highXaxisYpixel-originY)*cosphi + originY; + double lowXaxisXpixelR = (this.lowXaxisXpixel-originX)*cosphi + (this.lowXaxisYpixel-originY)*sinphi + originX; + double lowXaxisYpixelR = -(this.lowXaxisXpixel-originX)*sinphi + (this.lowXaxisYpixel-originY)*cosphi + originY; + double highYaxisXpixelR = (this.highYaxisXpixel-originX)*cosphi + (this.highYaxisYpixel-originY)*sinphi + originX; + double highYaxisYpixelR = -(this.highYaxisXpixel-originX)*sinphi + (this.highYaxisYpixel-originY)*cosphi + originY; + double lowYaxisXpixelR = -(this.lowYaxisXpixel-originX)*cosphi + (this.lowYaxisYpixel-originY)*sinphi + originX; + double lowYaxisYpixelR = (this.lowYaxisXpixel-originX)*sinphi + (this.lowYaxisYpixel-originY)*cosphi + originY; + + this.highXaxisXpixel = highXaxisXpixelR; + this.highXaxisYpixel = highXaxisYpixelR; + this.lowXaxisXpixel = lowXaxisXpixelR; + this.lowXaxisYpixel = lowXaxisYpixelR; + this.highYaxisXpixel = highYaxisXpixelR; + this.highYaxisYpixel = highYaxisYpixelR; + this.lowYaxisXpixel = lowYaxisXpixelR; + this.lowYaxisYpixel = lowYaxisYpixelR; + + // Rotate data points + for(int i=0; i<this.nData; i++){ + double xx = (this.xPosPixel[i]-originX)*cosphi + (this.yPosPixel[i]-originY)*sinphi + originX; + double yy = -(this.xPosPixel[i]-originX)*sinphi + (this.yPosPixel[i]-originY)*cosphi + originY; + this.xPosPixel[i] = xx; + this.yPosPixel[i] = yy; + } + + this.rotationDone = true; + } + + // This is called when the mouse has been pressed + // since it is empty nothing happens here. + public void mousePressed (MouseEvent me) {} + + // This is called when the mouse has been released + // since it is empty nothing happens here. + public void mouseReleased (MouseEvent me) {} + + // This is executed when the mouse enters the object. + // It will only be executed again when the mouse has left and then re-entered. + public void mouseEntered (MouseEvent me) { + this.mouseEntered = true; + repaint(); + } + + // This is executed when the mouse leaves the object. + public void mouseExited (MouseEvent me) { + this.mouseEntered = false; + repaint(); + } + + // Performs a cubic spline interpolation on the digitized points + private void interpolation(){ + // Dimension interpolation arrasys + this.xInterp = new double[this.nInterpPoints]; + this.yInterp = new double[this.nInterpPoints]; + + // Calculate x-axis interpolation points + double incr = (this.xPositions[this.nData-1] - this.xPositions[0])/(this.nInterpPoints - 1); + this.xInterp[0] = this.xPositions[0]; + for(int i=1; i<this.nInterpPoints-1; i++){ + this.xInterp[i] = this.xInterp[i-1] + incr; + } + this.xInterp[this.nInterpPoints-1] = this.xPositions[this.nData-1]; + + CubicSpline cs = new CubicSpline(this.xPositions, this.yPositions); + + // Interpolate y values + for(int i=0; i<this.nInterpPoints; i++)this.yInterp[i] = cs.interpolate(this.xInterp[i]); + + // Plot interpolated curve + if(this.plotOpt){ + int nMax = Math.max(this.nInterpPoints, this.nData); + double[][] plotData = PlotGraph.data(2, nMax); + + plotData[0] = this.xPositions; + plotData[1] = this.yPositions; + plotData[2] = this.xInterp; + plotData[3] = this.yInterp; + + PlotGraph pg = new PlotGraph(plotData); + + pg.setGraphTitle("Cubic Spline Interpolation of Digitised Points"); + pg.setGraphTitle2(this.imagePath); + + pg.setXaxisLegend("x"); + pg.setYaxisLegend("y"); + + int[] lineOpt = {0, 3}; + pg.setLine(lineOpt); + int[] pointOpt = {4, 0}; + pg.setPoint(pointOpt); + + pg.plot(); + + } + } + + // Checks for and removes all but one of identical points + public void checkForIdenticalPoints(){ + int nP = this.nData; + boolean test1 = true; + int ii = 0; + while(test1){ + boolean test2 = true; + int jj = ii+1; + while(test2){ + System.out.println("ii " + ii + " jj " + jj); + if(this.xPositions[ii]==this.xPositions[jj] && this.yPositions[ii]==this.yPositions[jj]){ + System.out.print("Class DigiGraph: two identical points, " + this.xPositions[ii] + ", " + this.yPositions[ii]); + System.out.println(", in data array at indices " + ii + " and " + jj + ", one point removed"); + + for(int i=jj; i<nP; i++){ + this.xPositions[i-1] = this.xPositions[i]; + this.yPositions[i-1] = this.yPositions[i]; + } + nP--; + if((nP-1)==ii)test2 = false; + } + else{ + jj++; + if(jj>=nP)test2 = false; + } + } + ii++; + if(ii>=nP-1)test1 = false; + } + + // Repack arrays if points deleted + if(nP!=this.nData){ + double[] holdX = new double[nP]; + double[] holdY = new double[nP]; + for(int i=0; i<nP; i++){ + holdX[i] = this.xPositions[i]; + holdY[i] = this.yPositions[i]; + } + this.xPositions = holdX; + this.yPositions = holdY; + this.nData = nP; + } + } + + // Plots the digitized points + private void plotDigitisedPoints(){ + + // Plot interpolated curve + double[][] plotData = PlotGraph.data(1, this.nData); + + plotData[0] = this.xPositions; + plotData[1] = this.yPositions; + + PlotGraph pg = new PlotGraph(plotData); + + pg.setGraphTitle("Plot of the Digitised Points"); + pg.setGraphTitle2(this.imagePath); + + pg.setXaxisLegend("x"); + pg.setYaxisLegend("y"); + + int[] lineOpt = {0}; + pg.setLine(lineOpt); + int[] pointOpt = {4}; + pg.setPoint(pointOpt); + + pg.plot(); + } +} + + + diff --git a/src/main/java/flanagan/io/FileChooser.java b/src/main/java/flanagan/io/FileChooser.java new file mode 100755 index 0000000000000000000000000000000000000000..2333f50dbe977ea81d53b12ca4a83f458077afc6 --- /dev/null +++ b/src/main/java/flanagan/io/FileChooser.java @@ -0,0 +1,158 @@ +/* +* Class FileChooser +* +* Methods for selecting and opening for reading a file through a dialogue box +* All folders and files may be displayed or a specific extension, e.g. txt, +* may be set (the extension filter uses the class FileTypeFilter which is +* the SUN JAVA filter, ExampleFileFilter, retitled) +* +* This is a sub-class of FileInput from which it inherits all the read methods +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 17 July 2004 +* REVISED: 11 June 2005 - Made a subclass of FileInput +* 30 November 2005, 2 July 2006, 20 September 2006, 7 July 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/FileChooser.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2006 - 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.io; + +import javax.swing.*; +import java.io.*; +import java.util.*; +import javax.swing.filechooser.*; + +public class FileChooser extends FileInput{ + + private File file; // file fo be selected + private String path = null; // path to directory from which the file is selected + // e.g. "C:\\Java\\flanagan + // default (path=null) - home directory + private String extn = null; // file type extension of files to be displayed + // default (extn=null) - all file types displayed + // constructor + // opens home directory + public FileChooser(){ + super(); + } + + // constructor + // opens directory given by path + public FileChooser(String path){ + super(); + this.path = path; + } + + // use JFileChooser to select the required file + // uses default prompt ("Select File") + public String selectFile(){ + return this.selectFile("Select File"); + } + + // use a JFileChooser to select the required file + // display user supplied prompt + public String selectFile(String prompt){ + + JFileChooser chooser = new JFileChooser(this.path); + + if(this.extn!=null){ + // Add filter + FileTypeFilter f = new FileTypeFilter(); + f.addExtension(extn); + f.setDescription(extn + " files"); + chooser.setFileFilter(f); + } + else{ + // enable all files displayed option + chooser.setAcceptAllFileFilterUsed(true); + } + + chooser.setDialogTitle(prompt); + chooser.showOpenDialog(null); + file = chooser.getSelectedFile(); + if(file==null){ + super.fileName = null; + super.stemName = null; + super.pathName = null; + super.dirPath = null; + super.fileFound=false; + } + else{ + super.pathName = file.toString(); + super.fileName = file.getName(); + super.dirPath = (file.getParentFile()).toString(); + int posDot = super.fileName.indexOf('.'); + if(posDot==-1){ + super.stemName = super.fileName; + } + else{ + super.stemName = super.fileName.substring(0, posDot); + } + + try{ + super.input = new BufferedReader(new FileReader(super.pathName)); + }catch(java.io.FileNotFoundException e){ + System.out.println(e); + super.fileFound=false; + } + } + + return super.fileName; + } + + // set path + public void setPath(String path){ + this.path = path; + } + + // get path + public String getPath(){ + return this.path; + } + + // set extension - display files with extension extn + public void setExtension(String extn){ + this.extn = extn; + } + + // display all file extensions + public void setAllExtensions(){ + this.extn = null; + } + + // get extension + public String getExtension(){ + return this.extn; + } + + // Displays dialogue box asking if you wish to exit program + // Answering yes end program + public static final synchronized void endProgram(){ + + int ans = JOptionPane.showConfirmDialog(null, "Do you wish to end the program", "End Program", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if(ans==0){ + System.exit(0); + } + else{ + JOptionPane.showMessageDialog(null, "Now you must press the appropriate escape key/s, e.g. Ctrl C, to exit this program"); + } + } +} diff --git a/src/main/java/flanagan/io/FileInput.java b/src/main/java/flanagan/io/FileInput.java new file mode 100755 index 0000000000000000000000000000000000000000..1188c464ce6d748d7389ddbe941523d987300b64 --- /dev/null +++ b/src/main/java/flanagan/io/FileInput.java @@ -0,0 +1,605 @@ +/* +* Class FileInput +* +* Methods for entering doubles, floats, BigDecimal, +* integers, long integers, short integers, bytes, +* booleans, Complexes, Phasors, lines (as String), +* words (as String) and chars from a text file. +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: July 2002 +* REVISED: 25 July 2004 +* 11 June 2005 - Made into superclass for revised FileChooser +* 13 September 2005 - numeric input - colon and semicolon stripping added +* 30 November 2005 - stem name method +* 21 February 2006 nextWord corrected +* 1 July 2006 - access status of FileInput() constructor changed +* 20 September 2006 - getPathName made public +* 27 June 2007 - Phasor input added +* 21-23 July 2007 - BigDecimal, BigInteger, short and byte added +* 26 February 2008 - removeSpaceAsDelimiter added +* 4 April 2008 - numberOfLines added +* 7 July 2008 - code tidying +* 8 July 2008 - get end of line status added +* 2 February 2009 - produce a copy of the file added +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/FileInput.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.io; + +import java.io.*; +import java.math.*; + +import flanagan.complex.Complex; +import flanagan.circuits.Phasor; + +public class FileInput{ + + // Instance variables + protected String fileName = " "; //input file name + protected String stemName = " "; //input file name without its extension + protected String pathName = " "; //input file path name + protected String dirPath = " "; //path to directory containing input file + protected String fullLine = " "; //current line in input file + protected String fullLineT = " "; //current line in input file trimmed of trailing spaces + protected BufferedReader input = null; //instance of BufferedReader + protected boolean testFullLine = false; //false if fullLine is empty + protected boolean testFullLineT = false; //false if fullLineT is empty + protected boolean eof = false; //true if reading beyond end of file attempted + protected boolean fileFound = true; //true if file named is found + protected boolean inputType = false; //false in input type is a String + //true if input type is numeric or separated char, i.e. double, float, int, long, char + protected boolean charType = false; //true if input type is a separated char + protected boolean space = true; //if true - a space is treated as a delimiter in reading a line of text + protected boolean supressMessage = false; //if true - read beyond end of file message suppressed + + // Constructor + // Constructor to enable sub-class FileChooser to function + public FileInput(){ + } + + // constructor for instances of this class + public FileInput(String pathName){ + this.pathName = pathName; + int posSlash = pathName.indexOf("//"); + int posBackSlash = pathName.indexOf("\\"); + if(posSlash!=-1 || posBackSlash!=-1){ + File file = new File(this.pathName); + this.fileName = file.getName(); + this.dirPath = (file.getParentFile()).toString(); + } + int posDot = this.fileName.indexOf('.'); + if(posDot==-1){ + this.stemName = this.fileName; + } + else{ + this.stemName = this.fileName.substring(0, posDot); + } + + try{ + this.input = new BufferedReader(new FileReader(this.pathName)); + }catch(java.io.FileNotFoundException e){ + System.out.println(e); + fileFound=false; + } + } + + // Methods + + // Get file path + public String getPathName(){ + return this.pathName; + } + + // Get file name + public String getFileName(){ + return this.fileName; + } + + // get file name without the extension + public String getStemName(){ + return this.stemName; + } + + // Get path to directory containing the file + public String getDirPath(){ + return this.dirPath; + } + + // Removes a space to the list of delimiters on reading a line of text + public void removeSpaceAsDelimiter(){ + this.space = false; + } + + // Restores a space from the list of delimiters on reading a line of text + public void restoreSpaceAsDelimiter(){ + this.space = true; + } + + // Copy the file + public final synchronized void copy(String copyFilename){ + FileOutput fout = new FileOutput(copyFilename); + int nLines = this.numberOfLines(); + for(int i=0; i<nLines; i++){ + String cline = this.readLine(); + fout.println(cline); + } + fout.close(); + } + + // Reads a double from the file + public final synchronized double readDouble(){ + this.inputType = true; + String word=""; + double dd=0.0D; + + if(!this.testFullLineT) this.enterLine(); + word = nextWord(); + + if(!eof)dd = Double.parseDouble(word.trim()); + + return dd; + } + + // Reads a float from the file + public final synchronized float readFloat(){ + this.inputType = true; + String word=""; + float ff=0.0F; + + if(!this.testFullLineT) this.enterLine(); + word = nextWord(); + if(!eof)ff = Float.parseFloat(word.trim()); + + return ff; + } + + + // Reads a BigDecimal from the file + public final synchronized BigDecimal readBigDecimal(){ + this.inputType = true; + String word=""; + BigDecimal big = null; + + if(!this.testFullLineT) this.enterLine(); + word = nextWord(); + if(!eof)big = new BigDecimal(word.trim()); + + return big; + } + + // Reads an integer (int) from the file + public final synchronized int readInt(){ + this.inputType = true; + String word=""; + int ii=0; + + if(!this.testFullLineT) this.enterLine(); + word = nextWord(); + if(!eof)ii = Integer.parseInt(word.trim()); + + return ii; + } + + // Reads a long integer from the file + public final synchronized long readLong(){ + this.inputType = true; + String word=""; + long ll=0L; + + if(!this.testFullLineT) this.enterLine(); + word = nextWord(); + if(!eof)ll = Long.parseLong(word.trim()); + + return ll; + } + + // Reads a BigInteger from the file + public final synchronized BigInteger readBigInteger(){ + this.inputType = true; + String word=""; + BigInteger big = null; + + if(!this.testFullLineT) this.enterLine(); + word = nextWord(); + if(!eof)big = new BigInteger(word.trim()); + + return big; + } + + // Reads a short integer from the file + public final synchronized short readShort(){ + this.inputType = true; + String word=""; + short ss=0; + + if(!this.testFullLineT) this.enterLine(); + word = nextWord(); + if(!eof)ss = Short.parseShort(word.trim()); + + return ss; + } + + // Reads a byte integer from the file + public final synchronized byte readByte(){ + this.inputType = true; + String word=""; + byte bb=0; + + if(!this.testFullLineT) this.enterLine(); + word = nextWord(); + if(!eof)bb = Byte.parseByte(word.trim()); + + return bb; + } + + // Reads a Complex from the file + // accepts strings 'real''sign''x''imag' and 'real''sign''x''.''imag' + // where x may be i or j + // and sign may be + or - + // e.g. 2+j3, 2+i3, + // no spaces are allowed within the complex number + // e.g. 2 + j3, 2 + i3 are NOT allowed + public final synchronized Complex readComplex(){ + + this.inputType = true; + String word=""; + Complex cc = null; + + if(!this.testFullLineT) this.enterLine(); + word = nextWord(); + + if(!eof)cc = Complex.parseComplex(word.trim()); + return cc; + } + + // Reads a Phasor from the file + // accepts strings 'magnitude'<'phase', 'magnitude'<'phase'deg, 'magnitude'<'phase'rad + // e.g. 1.23<34.1deg, -0.67<-56.7, 6.8e2<-0.22rad + public final synchronized Phasor readPhasor(){ + + this.inputType = true; + String word=""; + Phasor ph = null; + + if(!this.testFullLineT) this.enterLine(); + word = nextWord(); + + if(!eof)ph = Phasor.parsePhasor(word.trim()); + return ph; + } + + // Reads a boolean from the file + public final synchronized boolean readBoolean(){ + + boolean retB = true; + String retS = this.readWord(); + if(retS.equals("false") || retS.equals("FALSE")){ + retB = false; + } + else{ + if(retS.equals("true") || retS.equals("TRUE")){ + retB = true; + } + else{ + throw new IllegalArgumentException("attempted input neither true nor false"); + } + } + return retB; + } + + // Reads a word (a string between spaces) from the file + public final synchronized String readWord(){ + this.inputType = false; + String word=""; + + if(!this.testFullLineT) this.enterLine(); + if(this.fullLine.equals("")){ + word=""; + }else + { + word = nextWord(); + } + + return word; + } + + // Public method for reading a line from the file + public final synchronized String readLine(){ + this.inputType = false; + return this.readLineL(); + } + + // Protected method for reading a line from the file + protected final synchronized String readLineL(){ + String line=""; + try{ + line = input.readLine(); + }catch(java.io.IOException e){ + System.out.println(e); + } + if(line==null){ + if(!this.supressMessage)System.out.println("Attempt to read beyond the end of the file"); + eof=true; + line=""; + } + return line; + } + + // Reads a character, preceeded and followed by space, comma, colon or comma, from the file + public final synchronized char readChar(){ + inputType = true; + charType = true; + String word=""; + char ch=' '; + + if(!this.testFullLine) this.enterLine(); + word = nextWord(); + if(word.length()!=1)throw new IllegalArgumentException("attempt to read more than one character into type char"); + if(!eof)ch = word.charAt(0); + return ch; + } + + // Close file + public final synchronized void close(){ + if(fileFound){ + try{ + input.close(); + }catch(java.io.IOException e){ + System.out.println(e); + } + } + } + + // Get the end of line status. + public boolean eol(){ + boolean eol = false; + if(!this.testFullLineT)eol = true; + return eol; + } + + // Get the end of file status, eof. + public boolean eof(){ + return eof; + } + + // Get the file existence status, fileFound. + public boolean fileFound(){ + return fileFound; + } + + // enters a line from the file into the fullLine and fullLineT strings + protected final synchronized void enterLine(){ + int i=0; + + this.fullLine=this.readLineL(); + this.fullLineT=this.fullLine; + if(!this.fullLine.equals("")){ + i=this.fullLineT.length()-1; + while(this.fullLineT.charAt(i)==' ' && i>=0){ + this.fullLineT=this.fullLineT.substring(0,i); + i--; + } + } + } + + // reads the next word (a string between delimeters) from the String fullLine + protected final synchronized String nextWord(){ + this.testFullLine=true; + this.testFullLineT=true; + String word = ""; + int posspa=-1, postab=-1, possp=-1, poscom=-1, poscol=-1, possem=-1; + boolean test = true; + int len=this.fullLine.length(); + + // strip end of the word of any leading spaces, tabs or, if numerical input, commas, colons or semicolons + boolean test0 = true; + boolean test1 = false; + int pend =this.fullLine.length(); + while(test0){ + pend--; + if(this.fullLine.charAt(pend)==' ')test1=true; + if(this.fullLine.charAt(pend)=='\t')test1=true; + if(inputType){ + if(this.fullLine.charAt(pend)==',')test1=true; + if(this.fullLine.charAt(pend)==':')test1=true; + if(this.fullLine.charAt(pend)==';')test1=true; + } + if(test1){ + this.fullLine = this.fullLine.substring(0,pend); + } + else{ + test0=false; + } + test1=false; + } + + // strip front of the word of any leading spaces, tabs or, if numerical input, commas, colons or semicolons + test0 = true; + test1 = false; + while(test0){ + if(this.fullLine.charAt(0)==' ')test1=true; + if(this.fullLine.charAt(0)=='\t')test1=true; + if(inputType){ + if(this.fullLine.charAt(0)==',')test1=true; + if(this.fullLine.charAt(0)==':')test1=true; + if(this.fullLine.charAt(0)==';')test1=true; + + } + if(test1){ + this.fullLine = this.fullLine.substring(1); + } + else{ + test0=false; + } + test1=false; + } + + // find first space (if space allowed as delimiter), tab or, if numeric, comma, colon or semicolon + int lenPlus = this.fullLine.length() + 10; + if(this.space)posspa=this.fullLine.indexOf(' '); + postab=this.fullLine.indexOf('\t'); + int firstMin = lenPlus; + int secondMin = lenPlus; + int thirdMin = lenPlus; + if(this.space){ + if(posspa==-1 && postab==-1){ + firstMin = lenPlus; + } + else{ + if(posspa==-1){ + firstMin = postab; + } + else{ + if(postab==-1){ + firstMin = posspa; + } + else{ + firstMin = Math.min(posspa, postab); + } + } + } + } + else{ + if(postab!=-1){ + firstMin = postab; + } + } + if(this.inputType){ + poscom=this.fullLine.indexOf(','); + poscol=this.fullLine.indexOf(':'); + possem=this.fullLine.indexOf(';'); + if(poscom==-1 && poscol==-1){ + secondMin = lenPlus; + } + else{ + if(poscom==-1){ + secondMin = poscol; + } + else{ + if(poscol==-1){ + secondMin = poscom; + } + else{ + secondMin = Math.min(poscom, poscol); + } + } + } + if(possem==-1){ + thirdMin = lenPlus; + } + else{ + thirdMin = possem; + } + secondMin = Math.min(secondMin, thirdMin); + firstMin = Math.min(firstMin, secondMin); + + } + + + // remove first word first word from string + if(firstMin==lenPlus){ + word=this.fullLine; + this.fullLine=""; + this.testFullLine=false; + } + else{ + word=this.fullLine.substring(0,firstMin); + + if(firstMin+1>this.fullLine.length()){ + this.fullLine=""; + this.testFullLine=false; + } + else{ + this.fullLine=this.fullLine.substring(firstMin+1); + if(this.fullLine.length()==0)this.testFullLine=false; + } + } + if(this.testFullLineT){ + if(!this.testFullLine){ + this.testFullLineT=false; + this.fullLineT=""; + } + else{ + if(firstMin+1>this.fullLineT.length()){ + this.fullLineT=""; + this.testFullLineT=false; + } + } + } + + // return first word of the supplied string + return word; + } + + // reads the next char from the String fullLine + protected final synchronized char nextCharInString(){ + this.testFullLine=true; + char ch=' '; + boolean test = true; + + ch=this.fullLine.charAt(0); + this.fullLine=this.fullLine.substring(1); + if(this.fullLine.length()==0)this.testFullLine=false; + if(this.testFullLineT){ + this.fullLineT=this.fullLineT.substring(1); + if(this.fullLineT.length()==0)this.testFullLineT=false; + } + + return ch; + } + + // set supressMessage to true + public void setSupressMessageToTrue(){ + this.supressMessage = true; + } + + // set supressMessage to false + public void setSupressMessageToFalse(){ + this.supressMessage = false; + } + + // Returns the number of lines in the file + public final synchronized int numberOfLines(){ + FileInput fin = new FileInput(this.pathName); + fin.setSupressMessageToTrue(); + boolean test = true; + int nLines = 0; + while(test){ + String inputLine = fin.readLineL(); + if(fin.eof){ + test = false; + } + else{ + if(nLines==Integer.MAX_VALUE){ + System.out.println("Class FileInput; method numberOfLines; The number of lines is greater than the maximum integer value, " + Integer.MAX_VALUE); + System.out.println("-1 returned"); + nLines = -1; + } + else{ + nLines++; + } + } + } + fin.close(); + return nLines; + } +} diff --git a/src/main/java/flanagan/io/FileInputAsChar.java b/src/main/java/flanagan/io/FileInputAsChar.java new file mode 100755 index 0000000000000000000000000000000000000000..32a37c5243b7e9fbf7902e9afe7cb218f5f352f5 --- /dev/null +++ b/src/main/java/flanagan/io/FileInputAsChar.java @@ -0,0 +1,178 @@ +/* +* Class FileInputAsChar +* +* This class contains easy to use methods for reading in a file +* character by character, including non-print characters, e.g. line return character +* as a character (char), a wrapper class character (Character) or as the ISO code int equivalent (int); +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 13 September 2005 +* REVISED: +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/FileInputAsInput.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) November 2005 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.io; + +import java.io.*; +import flanagan.complex.Complex; + +public class FileInputAsChar{ + + // Instance variables + protected String fileName = ""; //input file name + protected String stemName = ""; //input file name without extension + protected String pathName = ""; //input file path name + protected String dirPath = ""; //path to directory containing input file + protected BufferedReader input = null; //instance of BufferedReader + protected boolean testFullLine = false; //false if fullLine is empty + protected boolean testFullLineT = false; //false if fullLineT is empty + protected boolean eof = false; //true if reading beyond end of file attempted + protected boolean fileFound = true; //true if file named is found + + // Constructor + public FileInputAsChar(String pathName){ + this.pathName = pathName; + int posSlash = pathName.indexOf("//"); + int posBackSlash = pathName.indexOf("\\"); + if(posSlash!=-1 || posBackSlash!=-1){ + File file = new File(this.pathName); + this.fileName = file.getName(); + this.dirPath = (file.getParentFile()).toString(); + } + int posDot = this.fileName.indexOf('.'); + if(posDot==-1){ + this.stemName = this.fileName; + } + else{ + this.stemName = this.fileName.substring(0, posDot); + } + + try{ + this.input = new BufferedReader(new FileReader(this.pathName)); + }catch(java.io.FileNotFoundException e){ + System.out.println(e); + fileFound=false; + } + } + + // Methods + + // Get file path + public String getPathName(){ + return this.pathName; + } + + // Get file name + public String getFileName(){ + return this.fileName; + } + + // Get file name without the extension + public String getStemName(){ + return this.stemName; + } + + // Get path to directory containing the file + public String getDirPath(){ + return this.dirPath; + } + + // Reads the next character from the file returning it as a char + public final synchronized char readchar(){ + int ich = -1; + char ch = '\u0000'; + try{ + ich = input.read(); + }catch(java.io.IOException e){ + System.out.println(e); + } + if(ich==-1){ + System.out.println("FileInputAsChar.readchar: attempt to read beyond end of file"); + eof = true; + ch = '\u0000'; + } + else{ + ch = (char) ich; + } + return ch; + } + + // Reads the next character from the file returning it as a Char + public final synchronized Character readCharacter(){ + int ich = -1; + char ch = '\u0000'; + Character wch = null; + + try{ + ich = input.read(); + }catch(java.io.IOException e){ + System.out.println(e); + } + if(ich==-1){ + System.out.println("FileInputAsChar.readChar: attempt to read beyond end of file"); + eof = true; + ch = '\u0000'; + wch = null; + } + else{ + ch = (char) ich; + wch = new Character(ch); + } + return wch; + } + + // Reads the next character from the file returning it as the ISO int code + public final synchronized int readint(){ + int ch = -1; + try{ + ch = input.read(); + }catch(java.io.IOException e){ + System.out.println(e); + } + if(ch==-1){ + System.out.println("FileInputAsChar.readint: attempt to read beyond end of file"); + eof = true; + } + return ch; + } + + // Close file + public final synchronized void close(){ + if(fileFound){ + try{ + input.close(); + }catch(java.io.IOException e){ + System.out.println(e); + } + } + } + + // Get the end of file status, eof. + public boolean eof(){ + return eof; + } + + // Get the file existence status, fileFound. + public boolean fileFound(){ + return fileFound; + } + +} diff --git a/src/main/java/flanagan/io/FileNameSelector.java b/src/main/java/flanagan/io/FileNameSelector.java new file mode 100755 index 0000000000000000000000000000000000000000..9560b2238eb0f8fa8a8b59754c5ee7ae8705c506 --- /dev/null +++ b/src/main/java/flanagan/io/FileNameSelector.java @@ -0,0 +1,181 @@ +/* +* Class FileNameSelector +* +* Methods for selecting the name and path of a file for use in a program +* The selected file is NOT opened +* +* See FileChooser for a class that contains methods that select and OPEN a file +* +* All folders and files may be displayed or a specific extension, e.g. txt, +* may be set (the extension filter uses the class FileTypeFilter which is +* the SUN JAVA filter, ExampleFileFilter, retitled) +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 13 September 2005 +* REVISED: 30 November 2005 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/FileNameSelector.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) September 2005 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.io; + +import javax.swing.*; +import java.io.*; +import java.util.*; +import javax.swing.filechooser.*; + +public class FileNameSelector{ + + private File file; // file whose name is to be selected + private String path = null; // path to directory from which the file is selected + // e.g. "C:\\Java\\flanagan + // default (path=null) - home directory + private String extn = null; // file type extension of files to be displayed + // default (extn=null) - all file types displayed + private String fileName = null; // selected file name + private String stemName = null; // selected file name without its extension + private String pathName = null; // selected file name path name + private String dirPath = null; // path to directory containing selectede file name + private boolean fileFound=false;// true if file named is found + + // constructor + // opens home directory + public FileNameSelector(){ + } + + // constructor + // opens directory given by path + public FileNameSelector(String path){ + this.path = path; + } + + // use JFileChooser to select the required file + // uses default prompt ("Select File") + public String selectFile(){ + return this.selectFile("Select File"); + } + + // use a JFileChooser to select the required file + // display user supplied prompt + public String selectFile(String prompt){ + + JFileChooser chooser = new JFileChooser(this.path); + + if(this.extn!=null){ + // Add filter + FileTypeFilter f = new FileTypeFilter(); + f.addExtension(extn); + f.setDescription(extn + " files"); + chooser.setFileFilter(f); + } + else{ + // enable all files displayed option + chooser.setAcceptAllFileFilterUsed(true); + } + + chooser.setDialogTitle(prompt); + chooser.showOpenDialog(null); + file = chooser.getSelectedFile(); + if(file==null){ + this.fileName = null; + this.stemName = null; + this.pathName = null; + this.dirPath = null; + this.fileFound=false; + } + else{ + this.pathName = file.toString(); + this.fileName = file.getName(); + this.dirPath = (file.getParentFile()).toString(); + int posDot = this.fileName.indexOf('.'); + if(posDot==-1){ + this.stemName = this.fileName; + } + else{ + this.stemName = this.fileName.substring(0, posDot); + } + } + + return this.fileName; + } + + // set path + public void setPath(String path){ + this.path = path; + } + + // get path + public String getPath(){ + return this.path; + } + + // set extension - display files with extension extn + public void setExtension(String extn){ + this.extn = extn; + } + + // display all file extensions + public void setAllExtensions(){ + this.extn = null; + } + + // get extension + public String getExtension(){ + return this.extn; + } + + // Get file path + public String getPathName(){ + return this.pathName; + } + + // Get file name + public String getFileName(){ + return this.fileName; + } + + // Get file name without its extension + public String getStemName(){ + return this.stemName; + } + + // Get path to directory containing the file + public String getDirPath(){ + return this.dirPath; + } + + // Get the file existence status, fileFound. + public boolean fileFound(){ + return fileFound; + } + + // Displays dialogue box asking if you wish to exit program + // Answering yes end program + public static final synchronized void endProgram(){ + + int ans = JOptionPane.showConfirmDialog(null, "Do you wish to end the program", "End Program", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if(ans==0){ + System.exit(0); + } + else{ + JOptionPane.showMessageDialog(null, "Now you must press the appropriate escape key/s, e.g. Ctrl C, to exit this program"); + } + } +} diff --git a/src/main/java/flanagan/io/FileOutput.java b/src/main/java/flanagan/io/FileOutput.java new file mode 100755 index 0000000000000000000000000000000000000000..5fba4abe50d4241cd31577c9992db536e758d1cc --- /dev/null +++ b/src/main/java/flanagan/io/FileOutput.java @@ -0,0 +1,2890 @@ +/* +* Class FileOutput +* +* Methods for writing doubles, floats, BigDecimals, +* integers, long integers, short integers, bytes, +* Strings, chars, booleans, Complex, Phasor, +* ErrorProp and ComplexErrorProp to a text file. +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: July 2002 +* UPDATED: 26 April 2004, 22 January 2006, 27 June 2007, 21-23 July 2007, 1 February 2009 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/FileOutput.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2009 +* +* PERMISSION TO COPY: +* +* Redistributions of this source code, or parts of, must retain the above +* copyright notice, this list of conditions and the following disclaimer. +* +* Redistribution in binary form of all or parts of this class, must reproduce +* the above copyright, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the distribution. +* +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all +* copies and associated documentation or publications. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.io; + +import java.io.*; +import java.math.*; +import java.text.*; +import java.util.*; + +import flanagan.complex.*; +import flanagan.circuits.Phasor; +import flanagan.analysis.ErrorProp; + +public class FileOutput{ + + // Instance variables + private String filename = ""; // output file name + private FileWriter fwoutput = null; // instance of FileWriter + private PrintWriter output = null; // instance of PrintWriter + private boolean append = false; // true data appended to a file, false new file + private char app = 'w'; // 'w' new file - overwrites an existing file of the same name + // 'a' append to existing file, creates a new file if file does not exist + // 'n' adds a number to file name. If file name of that number exists creates a file with next highest number added to name + private boolean fileExists = true; // = false if file of output filename does not already exist + + // Constructors + + public FileOutput(String filename, char app){ + this.filename = filename; + this.app = app; + this.setFilenames(filename, app); + } + + public FileOutput(String filename, String apps){ + this.filename = filename; + this.app = apps.charAt(0); + this.setFilenames(filename, app); + } + + public FileOutput(String filename){ + this.filename = filename; + this.app = 'w'; + this.setFilenames(filename, app); + } + + // Methods + + // Set the file names + private void setFilenames(String filename, char app){ + BufferedReader input0; + try{ + input0 = new BufferedReader(new FileReader(filename)); + }catch(FileNotFoundException e){ + this.fileExists = false; + } + + if(this.app == 'n'){ + boolean test = true; + int i = 0; + BufferedReader input; + String ext = ""; + String filename0 = ""; + + int idot=filename.indexOf('.'); + if(idot!=-1){ + ext += filename.substring(idot); + filename0 += filename.substring(0,idot); + } + else{ + filename0 += filename; + } + + while(test){ + i++; + filename=filename0+String.valueOf(i)+ext; + try{ + input = new BufferedReader(new FileReader(filename)); + }catch(FileNotFoundException e){ + test=false; + this.filename=filename; + } + } + } + + if(this.app == 'a'){ + this.append=true; + } + else{ + this.append = false; + } + try{ + fwoutput = new FileWriter(filename, this.append); + } + catch(IOException e){ + System.out.println(e); + } + + this.output = new PrintWriter(new BufferedWriter(fwoutput)); + } + + // Return filename + public String getFilename(){ + return this.filename; + } + + // Return file already exists check + // returns true if it does, false if it does not + public boolean checkFileAlreadyExists(){ + return this.fileExists; + } + + + // PRINT WITH NO FOLLOWING SPACE OR CHARACTER AND NO LINE RETURN + + // Prints character, no line return + public final synchronized void print(char ch){ + this.output.print(ch); + } + + // Prints character, no line return, fixed field length + public final synchronized void print(char ch, int f){ + String ss =""; + ss = ss + ch; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + + // Prints string, no line return + public final synchronized void print(String word){ + this.output.print(word); + } + + + // Prints string, no line return, fixed field length + public final synchronized void print(String word, int f){ + String ss =""; + ss = ss + word; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + // Prints double, no line return + public final synchronized void print(double dd){ + this.output.print(dd); + } + + // Prints double, no line return, fixed field length + public final synchronized void print(double dd, int f){ + String ss =""; + ss = ss + dd; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + + // Prints float, no line return + public final synchronized void print(float ff){ + this.output.print(ff); + } + + // Prints float, no line return, fixed field length + public final synchronized void print(float ff, int f){ + String ss =""; + ss = ss + ff; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + + // Prints BigDecimal, no line return + public final synchronized void print(BigDecimal big){ + this.output.print(big.toString()); + } + + // Prints BigDecimal big, no line return, fixed field length + public final synchronized void print(BigDecimal big , int f){ + String ss =""; + ss = ss + big.toString(); + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + + // Prints BigInteger, no line return + public final synchronized void print(BigInteger big){ + this.output.print(big.toString()); + } + + // Prints BigInteger big, no line return, fixed field length + public final synchronized void print(BigInteger big , int f){ + String ss =""; + ss = ss + big.toString(); + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + + // Prints Complex, no line return + public final synchronized void print(Complex ff){ + this.output.print(ff.toString()); + } + + // Prints Complex, no line return, fixed field length + public final synchronized void print(Complex ff, int f){ + String ss =""; + ss = ss + ff; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + + // Prints Phasor, no line return + public final synchronized void print(Phasor ff){ + this.output.print(ff.toString()); + } + + // Prints Phasor, no line return, fixed field length + public final synchronized void print(Phasor ff, int f){ + String ss =""; + ss = ss + ff; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + + // Prints ErrorProp, no line return + public final synchronized void print(ErrorProp ff){ + this.output.print(ff.toString()); + } + + // Prints ErrorProp, no line return, fixed field length + public final synchronized void print(ErrorProp ff, int f){ + String ss =""; + ss = ss + ff; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + + // Prints ComplexErrorProp, no line return + public final synchronized void print(ComplexErrorProp ff){ + this.output.print(ff.toString()); + } + + // Prints ComplexErrorProp, no line return, fixed field length + public final synchronized void print(ComplexErrorProp ff, int f){ + String ss =""; + ss = ss + ff; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + + // Prints int, no line return + public final synchronized void print(int ii){ + this.output.print(ii); + } + + // Prints int, no line return, fixed field length + public final synchronized void print(int ii, int f){ + String ss =""; + ss = ss + ii; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + + // Prints long integer, no line return + public final synchronized void print(long ll){ + this.output.print(ll); + } + + // Prints long integer, no line return, fixed field length + public final synchronized void print(long ll, int f){ + String ss =""; + ss = ss + ll; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + + // Prints short integer, no line return + public final synchronized void print(short ss){ + this.output.print(ss); + } + + // Prints short integer, no line return, fixed field length + public final synchronized void print(short si, int f){ + String ss =""; + ss = ss + si; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + + // Prints byte integer, no line return + public final synchronized void print(byte by){ + this.output.print(by); + } + + // Prints short integer, no line return, fixed field length + public final synchronized void print(byte by, int f){ + String ss =""; + ss = ss + by; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + + // Prints boolean, no line return + public final synchronized void print(boolean bb){ + this.output.print(bb); + } + + // Prints boolean, no line return, fixed field length + public final synchronized void print(boolean bb, int f){ + String ss =""; + ss = ss + bb; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + + // Prints array of doubles, no line return + public final synchronized void print(double[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + } + } + + // Prints array of floats, no line return + public final synchronized void print(float[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + } + } + + // Prints array of BigDecimal, no line return + public final synchronized void print(BigDecimal[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + } + } + + // Prints array of BigInteger, no line return + public final synchronized void print(BigInteger[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + } + } + + // Prints array of int, no line return + public final synchronized void print(int[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + } + } + + // Prints array of short, no line return + public final synchronized void print(short[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + } + } + + // Prints array of byte, no line return + public final synchronized void print(byte[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + } + } + + // Prints array of char, no line return + public final synchronized void print(char[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + } + } + + // Prints array of boolean, no line return + public final synchronized void print(boolean[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + } + } + + // Prints array of Strings, no line return + public final synchronized void print(String[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + } + } + + // Prints array of Complex, no line return + public final synchronized void print(Complex[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + } + } + + // Prints array of Phasor, no line return + public final synchronized void print(Phasor[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + } + } + + // Prints array of ErrorProp, no line return + public final synchronized void print(ErrorProp[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + } + } + + // Prints array of ComplexErrorProp, no line return + public final synchronized void print(ComplexErrorProp[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + } + } + + + // Prints array of doubles, no line return, fixed field length + public final synchronized void print(double[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints array of floats, no line return, fixed field length + public final synchronized void print(float[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints array of BigDecimal, no line return, fixed field length + public final synchronized void print(BigDecimal[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints array of BigInteger, no line return, fixed field length + public final synchronized void print(BigInteger[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints array of long, no line return, fixed field length + public final synchronized void print(long[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints array of int, no line return, fixed field length + public final synchronized void print(int[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints array of short, no line return, fixed field length + public final synchronized void print(short[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints array of byte, no line return, fixed field length + public final synchronized void print(byte[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints array of char, no line return, fixed field length + public final synchronized void print(char[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints array of boolean, no line return, fixed field length + public final synchronized void print(boolean[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints array of Strings, no line return, fixed field length + public final synchronized void print(String[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints array of Complex, no line return, fixed field length + public final synchronized void print(Complex[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints array of Phasor, no line return, fixed field length + public final synchronized void print(Phasor[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints array of ErrorProp, no line return, fixed field length + public final synchronized void print(ErrorProp[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints array of ComplexErrorProp, no line return, fixed field length + public final synchronized void print(ComplexErrorProp[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + } + } + + // Prints date and time (no line return); + public final synchronized void dateAndTime(){ + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + + this.output.print("This file was created at "); + this.output.print(tim); + this.output.print(" on "); + this.output.print(day); + } + + // Prints file title (title), date and time (no line return); + public final synchronized void dateAndTime(String title){ + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + + this.output.print("This file, "+title+", was created at "); + this.output.print(tim); + this.output.print(" on "); + this.output.print(day); + } + + // PRINT WITH SPACE (NO LINE RETURN) + // Prints character plus space, no line return + public final synchronized void printsp(char ch){ + this.output.print(ch); + this.output.print(" "); + } + + // Prints string plus space, no line return + public final synchronized void printsp(String word){ + this.output.print(word + " "); + } + + // Prints double plus space, no line return + public final synchronized void printsp(double dd){ + this.output.print(dd); + this.output.print(" "); + } + + // Prints float plus space, no line return + public final synchronized void printsp(float ff){ + this.output.print(ff); + this.output.print(" "); + } + + // Prints BigDecimal plus space, no line return + public final synchronized void printsp(BigDecimal big){ + this.output.print(big.toString()); + this.output.print(" "); + } + + // Prints BigInteger plus space, no line return + public final synchronized void printsp(BigInteger big){ + this.output.print(big.toString()); + this.output.print(" "); + } + + // Prints Complex plus space, no line return + public final synchronized void printsp(Complex ff){ + this.output.print(ff.toString()); + this.output.print(" "); + } + + // Prints Phasor plus space, no line return + public final synchronized void printsp(Phasor ff){ + this.output.print(ff.toString()); + this.output.print(" "); + } + + // Prints ErrorProp plus space, no line return + public final synchronized void printsp(ErrorProp ff){ + this.output.print(ff.toString()); + this.output.print(" "); + } + + // Prints ComplexErrorProp plus space, no line return + public final synchronized void printsp(ComplexErrorProp ff){ + this.output.print(ff.toString()); + this.output.print(" "); + } + + // Prints int plus space, no line return + public final synchronized void printsp(int ii){ + this.output.print(ii); + this.output.print(" "); + } + + // Prints long integer plus space, no line return + public final synchronized void printsp(long ll){ + this.output.print(ll); + this.output.print(" "); + } + + // Prints short integer plus space, no line return + public final synchronized void printsp(short ss){ + this.output.print(ss); + this.output.print(" "); + } + + // Prints byte integer plus space, no line return + public final synchronized void printsp(byte by){ + this.output.print(by); + this.output.print(" "); + } + + // Prints boolean plus space, no line return + public final synchronized void printsp(boolean bb){ + this.output.print(bb); + this.output.print(" "); + } + + // Prints space, no line return + public final synchronized void printsp(){ + this.output.print(" "); + } + + // Prints array of doubles, separated by spaces + public final synchronized void printsp(double[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + // Prints array of floats, separated by spaces + public final synchronized void printsp(float[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + // Prints array of BigDecimal, separated by spaces + public final synchronized void printsp(BigDecimal[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + // Prints array of BigInteger, separated by spaces + public final synchronized void printsp(BigInteger[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + // Prints array of long, separated by spaces + public final synchronized void printsp(long[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + // Prints array of int, separated by spaces + public final synchronized void printsp(int[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + // Prints array of char, separated by spaces + public final synchronized void printsp(char[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + // Prints array of short, separated by spaces + public final synchronized void printsp(short[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + // Prints array of byte, separated by spaces + public final synchronized void printsp(byte[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + // Prints array of boolean, separated by spaces + public final synchronized void printsp(boolean[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + // Prints array of Strings, separated by spaces + public final synchronized void printsp(String[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + // Prints array of Complex, separated by spaces + public final synchronized void printsp(Complex[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + // Prints array of Phasor, separated by spaces + public final synchronized void printsp(Phasor[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + // Prints array of ErrorProp, separated by spaces + public final synchronized void printsp(ErrorProp[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + // Prints array of ComplexErrorProp, separated by spaces + public final synchronized void printsp(ComplexErrorProp[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(" "); + } + } + + + // Prints date and time (plus space, no line return); + public final synchronized void dateAndTimesp(){ + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + + this.output.print("This file was created at "); + this.output.print(tim); + this.output.print(" on "); + this.output.print(day); + this.output.print(" "); + } + + // Prints file title (title), date and time (no line return); + public final synchronized void dateAndTimesp(String title){ + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + + this.output.print("This file, "+title+", was created at "); + this.output.print(tim); + this.output.print(" on "); + this.output.print(day); + this.output.print(" "); + } + + // PRINT WITH LINE RETURN + // Prints character with line return + public final synchronized void println(char ch){ + this.output.println(ch); + } + + // Prints string with line return + public final synchronized void println(String word){ + this.output.println(word); + } + + // Prints double with line return + public final synchronized void println(double dd){ + this.output.println(dd); + } + + // Prints float with line return + public final synchronized void println(float ff){ + this.output.println(ff); + } + + // Prints BigDecimal with line return + public final synchronized void println(BigDecimal big){ + this.output.println(big.toString()); + } + + // Prints BigInteger with line return + public final synchronized void println(BigInteger big){ + this.output.println(big.toString()); + } + + // Prints Complex with line return + public final synchronized void println(Complex ff){ + this.output.println(ff.toString()); + } + + // Prints Phasor with line return + public final synchronized void println(Phasor ff){ + this.output.println(ff.toString()); + } + + // Prints ErrorProp with line return + public final synchronized void println(ErrorProp ff){ + this.output.println(ff.toString()); + } + + // Prints ComplexErrorProp with line return + public final synchronized void println(ComplexErrorProp ff){ + this.output.println(ff.toString()); + } + + // Prints int with line return + public final synchronized void println(int ii){ + this.output.println(ii); + } + + // Prints long integer with line return + public final synchronized void println(long ll){ + this.output.println(ll); + } + + // Prints short integer with line return + public final synchronized void println(short ss){ + this.output.println(ss); + } + + // Prints byte integer with line return + public final synchronized void println(byte by){ + this.output.println(by); + } + + // Prints boolean with line return + public final synchronized void println(boolean bb){ + this.output.println(bb); + } + + // Prints line return + public final synchronized void println(){ + this.output.println(""); + } + + // Prints array of doubles, each followed by a line return + public final synchronized void println(double[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + // Prints array of floats, each followed by a line return + public final synchronized void println(float[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + // Prints array of BigDecimal, each followed by a line return + public final synchronized void println(BigDecimal[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + // Prints array of BigInteger, each followed by a line return + public final synchronized void println(BigInteger[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + // Prints array of long, each followed by a line return + public final synchronized void println(long[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + // Prints array of int, each followed by a line return + public final synchronized void println(int[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + // Prints array of short, each followed by a line return + public final synchronized void println(short[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + // Prints array of byte, each followed by a line return + public final synchronized void println(byte[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + // Prints array of char, each followed by a line return + public final synchronized void println(char[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + // Prints array of boolean, each followed by a line return + public final synchronized void println(boolean[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + // Prints array of Strings, each followed by a line return + public final synchronized void println(String[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + // Prints array of Complex, each followed by a line return + public final synchronized void println(Complex[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + // Prints array of Phasor, each followed by a line return + public final synchronized void println(Phasor[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + // Prints array of ErrorProp, each followed by a line return + public final synchronized void println(ErrorProp[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + // Prints array of ComplexErrorProp, each followed by a line return + public final synchronized void println(ComplexErrorProp[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.println(array[i]); + } + } + + + // Prints date and time as date-month-year hour:minute:second (with line return); + public final synchronized void dateAndTimeln(){ + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + + this.output.print("This file, "+this.filename+", was created at "); + this.output.print(tim); + this.output.print(" on "); + this.output.println(day); + } + + // Prints file title (title), date and time (with line return); + public final synchronized void dateAndTimeln(String title){ + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + + this.output.print("This file, "+title+", was created at "); + this.output.print(tim); + this.output.print(" on "); + this.output.println(day); + } + + // PRINT WITH FOLLOWING TAB, NO LINE RETURN + // Prints character plus tab, no line return + public final synchronized void printtab(char ch){ + this.output.print(ch); + this.output.print("\t"); + } + + // Prints character plus tab, no line return, fixed field length + public final synchronized void printtab(char ch, int f){ + String ss =""; + ss = ss + ch; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints string plus tab, no line return + public final synchronized void printtab(String word){ + this.output.print(word + "\t"); + } + + // Prints string plus tab, no line return, fixed field length + public final synchronized void printtab(String word, int f){ + String ss =""; + ss = ss + word; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints double plus tab, no line return + public final synchronized void printtab(double dd){ + this.output.print(dd); + this.output.print("\t"); + } + + // Prints double plus tab, fixed field length, fixed field length + public final synchronized void printtab(double dd, int f){ + String ss =""; + ss = ss + dd; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints float plus tab, no line return + public final synchronized void printtab(float ff){ + this.output.print(ff); + this.output.print("\t"); + } + + // Prints float plus tab, no line return, fixed field length + public final synchronized void printtab(float ff, int f){ + String ss =""; + ss = ss + ff; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints BigDecimal plus tab, no line return + public final synchronized void printtab(BigDecimal big){ + this.output.print(big.toString()); + this.output.print("\t"); + } + + // Prints BigDecimal plus tab, no line return, fixed field length + public final synchronized void printtab(BigDecimal big, int f){ + String ss =""; + ss = ss + big.toString(); + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints BigInteger plus tab, no line return + public final synchronized void printtab(BigInteger big){ + this.output.print(big.toString()); + this.output.print("\t"); + } + + // Prints BigInteger plus tab, no line return, fixed field length + public final synchronized void printtab(BigInteger big, int f){ + String ss =""; + ss = ss + big.toString(); + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints Complex plus tab, no line return + public final synchronized void printtab(Complex ff){ + this.output.print(ff.toString()); + this.output.print("\t"); + } + + // Prints Phasor plus tab, no line return + public final synchronized void printtab(Phasor ff){ + this.output.print(ff.toString()); + this.output.print("\t"); + } + + // Prints Complex plus tab, no line return, fixed field length + public final synchronized void printtab(Complex ff, int f){ + String ss =""; + ss = ss + ff; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints Phasor plus tab, no line return, fixed field length + public final synchronized void printtab(Phasor ff, int f){ + String ss =""; + ss = ss + ff; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints ErrorProp plus tab, no line return + public final synchronized void printtab(ErrorProp ff){ + this.output.print(ff.toString()); + this.output.print("\t"); + } + + // Prints ErrorProp plus tab, no line return, fixed field length + public final synchronized void printtab(ErrorProp ff, int f){ + String ss =""; + ss = ss + ff; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints ComplexErrorProp plus tab, no line return + public final synchronized void printtab(ComplexErrorProp ff){ + this.output.print(ff.toString()); + this.output.print("\t"); + } + + // Prints ComplexErrorProp plus tab, no line return, fixed field length + public final synchronized void printtab(ComplexErrorProp ff, int f){ + String ss =""; + ss = ss + ff; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints int plus tab, no line return + public final synchronized void printtab(int ii){ + this.output.print(ii); + this.output.print("\t"); + } + + // Prints int plus tab, no line return, fixed field length + public final synchronized void printtab(int ii, int f){ + String ss =""; + ss = ss + ii; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints long integer plus tab, no line return + public final synchronized void printtab(long ll){ + this.output.print(ll); + this.output.print("\t"); + } + + // Prints long integer plus tab, no line return, fixed field length + public final synchronized void printtab(long ll, int f){ + String ss =""; + ss = ss + ll; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints short integer plus tab, no line return + public final synchronized void printtab(short ss){ + this.output.print(ss); + this.output.print("\t"); + } + + // Prints short integer plus tab, no line return, fixed field length + public final synchronized void printtab(short si, int f){ + String ss =""; + ss = ss + si; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints byte integer plus tab, no line return + public final synchronized void printtab(byte by){ + this.output.print(by); + this.output.print("\t"); + } + + // Prints byte integer plus tab, no line return, fixed field length + public final synchronized void printtab(byte by, int f){ + String ss =""; + ss = ss + by; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints boolean plus tab, no line return + public final synchronized void printtab(boolean bb){ + this.output.print(bb); + this.output.print("\t"); + } + + // Prints boolean plus tab, no line return, fixed field length + public final synchronized void printtab(boolean bb, int f){ + String ss =""; + ss = ss + bb; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + + // Prints tab, no line return + public final synchronized void printtab(){ + this.output.print("\t"); + } + + // Prints array of doubles, tab, no line return, fixed field length + public final synchronized void printtab(double[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + // Prints array of floats, tab, no line return, fixed field length + public final synchronized void printtab(float[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + // Prints array of BigDecimal, tab, no line return, fixed field length + public final synchronized void printtab(BigDecimal[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i].toString(); + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + // Prints array of BigInteger, tab, no line return, fixed field length + public final synchronized void printtab(BigInteger[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i].toString(); + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + + // Prints array of long, tab, no line return, fixed field length + public final synchronized void printtab(long[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + // Prints array of int, tab, no line return, fixed field length + public final synchronized void printtab(int[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + // Prints array of short, tab, no line return, fixed field length + public final synchronized void printtab(short[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + // Prints array of byte, tab, no line return, fixed field length + public final synchronized void printtab(byte[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + // Prints array of char, tab, no line return, fixed field length + public final synchronized void printtab(char[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + // Prints array of boolean, tab, no line return, fixed field length + public final synchronized void printtab(boolean[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + // Prints array of Strings, tab, no line return, fixed field length + public final synchronized void printtab(String[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + // Prints array of Complex, tab, no line return, fixed field length + public final synchronized void printtab(Complex[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + // Prints array of Phasor, tab, no line return, fixed field length + public final synchronized void printtab(Phasor[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + // Prints array of ErrorProp, tab, no line return, fixed field length + public final synchronized void printtab(ErrorProp[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + // Prints array of ComplexErrorProp, tab, no line return, fixed field length + public final synchronized void printtab(ComplexErrorProp[] array, int f){ + int n = array.length; + for(int i=0; i<n; i++){ + String ss =""; + ss = ss + array[i]; + ss = FileOutput.setField(ss,f); + this.output.print(ss); + this.output.print("\t"); + } + } + + // Prints array of doubles, tab, no line return + public final synchronized void printtab(double[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print("\t"); + } + } + + // Prints array of floats, tab, no line return + public final synchronized void printtab(float[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print("\t"); + } + } + + // Prints array of BigDecimal, tab, no line return + public final synchronized void printtab(BigDecimal[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i].toString()); + this.output.print("\t"); + } + } + + // Prints array of BigInteger, tab, no line return + public final synchronized void printtab(BigInteger[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i].toString()); + this.output.print("\t"); + } + } + + // Prints array of long, tab, no line return + public final synchronized void printtab(long[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print("\t"); + } + } + + // Prints array of int, tab, no line return + public final synchronized void printtab(int[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print("\t"); + } + } + + // Prints array of char, tab, no line return + public final synchronized void printtab(char[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print("\t"); + } + } + + // Prints array of boolean, tab, no line return + public final synchronized void printtab(boolean[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print("\t"); + } + } + + // Prints array of Strings, tab, no line return + public final synchronized void printtab(String[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print("\t"); + } + } + + // Prints array of Complex, tab, no line return + public final synchronized void printtab(Complex[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print("\t"); + } + } + + // Prints array of Phasor, tab, no line return + public final synchronized void printtab(Phasor[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print("\t"); + } + } + + // Prints array of ErrorProp, tab, no line return + public final synchronized void printtab(ErrorProp[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print("\t"); + } + } + + // Prints array of ComplexErrorProp, tab, no line return + public final synchronized void printtab(ComplexErrorProp[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print("\t"); + } + } + + + // Prints date and time (plus tab, no line return); + public final synchronized void dateAndTimetab(){ + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + + this.output.print("This file was created at "); + this.output.print(tim); + this.output.print(" on "); + this.output.print(day); + this.output.print("\t"); + } + + // Prints file title (title), date and time (plus tab, no line return); + public final synchronized void dateAndTimetab(String title){ + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + + this.output.print("This file, "+title+", was created at "); + this.output.print(tim); + this.output.print(" on "); + this.output.print(day); + this.output.print("\t"); + } + + // PRINT FOLLOWED BY A COMMA, NO LINE RETURN + // Prints character plus comma, no line return + public final synchronized void printcomma(char ch){ + this.output.print(ch); + this.output.print(","); + } + + // Prints string plus comma, no line return + public final synchronized void printcomma(String word){ + this.output.print(word + ","); + } + + // Prints double plus comma, no line return + public final synchronized void printcomma(double dd){ + this.output.print(dd); + this.output.print(","); + } + + // Prints float plus comma, no line return + public final synchronized void printcomma(float ff){ + this.output.print(ff); + this.output.print(","); + } + + // Prints BigDecimal plus comma, no line return + public final synchronized void printcomma(BigDecimal big){ + this.output.print(big.toString()); + this.output.print(","); + } + + // Prints BigInteger plus comma, no line return + public final synchronized void printcomma(BigInteger big){ + this.output.print(big.toString()); + this.output.print(","); + } + + // Prints Complex plus comma, no line return + public final synchronized void printcomma(Complex ff){ + this.output.print(ff.toString()); + this.output.print(","); + } + + // Prints Phasor plus comma, no line return + public final synchronized void printcomma(Phasor ff){ + this.output.print(ff.toString()); + this.output.print(","); + } + + // Prints ErrorProp plus comma, no line return + public final synchronized void printcomma(ErrorProp ff){ + this.output.print(ff.toString()); + this.output.print(","); + } + + // Prints ComplexErrorProp plus comma, no line return + public final synchronized void printcomma(ComplexErrorProp ff){ + this.output.print(ff.toString()); + this.output.print(","); + } + + // Prints int plus comma, no line return + public final synchronized void printcomma(int ii){ + this.output.print(ii); + this.output.print(","); + } + + // Prints long integer plus comma, no line return + public final synchronized void printcomma(long ll){ + this.output.print(ll); + this.output.print(","); + } + + // Prints boolean plus comma, no line return + public final synchronized void printcomma(boolean bb){ + this.output.print(bb); + this.output.print(","); + } + + // Prints short integer plus comma, no line return + public final synchronized void printcomma(short ss){ + this.output.print(ss); + this.output.print(","); + } + + // Prints byte integer plus comma, no line return + public final synchronized void printcomma(byte by){ + this.output.print(by); + this.output.print(","); + } + + // Prints comma, no line return + public final synchronized void printcomma(){ + this.output.print(","); + } + + // Prints array of doubles, each separated by a comma + public final synchronized void printcomma(double[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(","); + } + } + + // Prints array of floats, each separated by a comma + public final synchronized void printcomma(float[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(","); + } + } + + // Prints array of BigDecimal, each separated by a comma + public final synchronized void printcomma(BigDecimal[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i].toString()); + this.output.print(","); + } + } + + // Prints array of BigInteger, each separated by a comma + public final synchronized void printcomma(BigInteger[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i].toString()); + this.output.print(","); + } + } + + // Prints array of long, each separated by a comma + public final synchronized void printcomma(long[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(","); + } + } + + // Prints array of int, each separated by a comma + public final synchronized void printcomma(int[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(","); + } + } + + // Prints array of short, each separated by a comma + public final synchronized void printcomma(short[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(","); + } + } + + // Prints array of byte, each separated by a comma + public final synchronized void printcomma(byte[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(","); + } + } + + // Prints array of char, each separated by a comma + public final synchronized void printcomma(char[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(","); + } + } + + // Prints array of boolean, each separated by a comma + public final synchronized void printcomma(boolean[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(","); + } + } + + // Prints array of Strings, each separated by a comma + public final synchronized void printcomma(String[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(","); + } + } + + // Prints array of Complex, each separated by a comma + public final synchronized void printcomma(Complex[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(","); + } + } + + // Prints array of Phasor, each separated by a comma + public final synchronized void printcomma(Phasor[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(","); + } + } + + // Prints array of ErrorProp, each separated by a comma + public final synchronized void printcomma(ErrorProp[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(","); + } + } + + // Prints array of ComplexErrorProp, each separated by a comma + public final synchronized void printcomma(ComplexErrorProp[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(","); + } + } + + + // Prints date and time (plus comma, no line return); + public final synchronized void dateAndTimecomma(){ + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + + this.output.print("This file was created at "); + this.output.print(tim); + this.output.print(" on "); + this.output.print(day); + this.output.print(","); + } + + // Prints file title (title), date and time (plus comma, no line return); + public final synchronized void dateAndTimecomma(String title){ + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + + this.output.print("This file, "+title+", was created at "); + this.output.print(tim); + this.output.print(" on "); + this.output.print(day); + this.output.print(","); + } + + // PRINT FOLLOWED BY A SEMICOLON, NO LINE RETURN + // Prints character plus semicolon, no line return + public final synchronized void printsc(char ch){ + this.output.print(ch); + this.output.print(";"); + } + + // Prints string plus semicolon, no line return + public final synchronized void printsc(String word){ + this.output.print(word + ";"); + } + + // Prints double plus semicolon, no line return + public final synchronized void printsc(double dd){ + this.output.print(dd); + this.output.print(";"); + } + + // Prints float plus semicolon, no line return + public final synchronized void printsc(float ff){ + this.output.print(ff); + this.output.print(";"); + } + + // Prints BigDecimal plus semicolon, no line return + public final synchronized void printsc(BigDecimal big){ + this.output.print(big.toString()); + this.output.print(";"); + } + + // Prints BigInteger plus semicolon, no line return + public final synchronized void printsc(BigInteger big){ + this.output.print(big.toString()); + this.output.print(";"); + } + + // Prints Complex plus semicolon, no line return + public final synchronized void printsc(Complex ff){ + this.output.print(ff.toString()); + this.output.print(";"); + } + + // Prints Phasor plus semicolon, no line return + public final synchronized void printsc(Phasor ff){ + this.output.print(ff.toString()); + this.output.print(";"); + } + + // Prints ErrorProp plus semicolon, no line return + public final synchronized void printsc(ErrorProp ff){ + this.output.print(ff.toString()); + this.output.print(";"); + } + + // Prints ComplexErrorProp plus semicolon, no line return + public final synchronized void printsc(ComplexErrorProp ff){ + this.output.print(ff.toString()); + this.output.print(";"); + } + + // Prints int plus semicolon, no line return + public final synchronized void printsc(int ii){ + this.output.print(ii); + this.output.print(";"); + } + + // Prints long integer plus semicolon, no line return + public final synchronized void printsc(long ll){ + this.output.print(ll); + this.output.print(";"); + } + + // Prints short integer plus semicolon, no line return + public final synchronized void printsc(short ss){ + this.output.print(ss); + this.output.print(";"); + } + + // Prints byte integer plus semicolon, no line return + public final synchronized void printsc(byte by){ + this.output.print(by); + this.output.print(";"); + } + + // Prints boolean plus semicolon, no line return + public final synchronized void printsc(boolean bb){ + this.output.print(bb); + this.output.print(";"); + } + + // Prints semicolon, no line return + public final synchronized void printsc(){ + this.output.print(";"); + } + + // Prints array of doubles, each separated by a semicolon + public final synchronized void printsc(double[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(";"); + } + } + + // Prints array of floats, each separated by a semicolon + public final synchronized void printsc(float[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(";"); + } + } + + // Prints array of BigDecimal, each separated by a semicolon + public final synchronized void printsc(BigDecimal[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i].toString()); + this.output.print(";"); + } + } + + // Prints array of BigInteger, each separated by a semicolon + public final synchronized void printsc(BigInteger[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i].toString()); + this.output.print(";"); + } + } + + // Prints array of long, each separated by a semicolon + public final synchronized void printsc(long[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(";"); + } + } + + // Prints array of short, each separated by a semicolon + public final synchronized void printsc(short[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(";"); + } + } + + // Prints array of byte, each separated by a semicolon + public final synchronized void printsc(byte[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(";"); + } + } + + // Prints array of int, each separated by a semicolon + public final synchronized void printsc(int[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(";"); + } + } + + // Prints array of char, each separated by a semicolon + public final synchronized void printsc(char[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(";"); + } + } + + // Prints array of boolean, each separated by a semicolon + public final synchronized void printsc(boolean[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(";"); + } + } + + // Prints array of Strings, each separated by a semicolon + public final synchronized void printsc(String[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(";"); + } + } + + // Prints array of Complex, each separated by a semicolon + public final synchronized void printsc(Complex[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(";"); + } + } + + // Prints array of Phasor, each separated by a semicolon + public final synchronized void printsc(Phasor[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(";"); + } + } + + // Prints array of ErrorProp, each separated by a semicolon + public final synchronized void printsc(ErrorProp[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(";"); + } + } + + // Prints array of ComplexErrorProp, each separated by a semicolon + public final synchronized void printsc(ComplexErrorProp[] array){ + int n = array.length; + for(int i=0; i<n; i++){ + this.output.print(array[i]); + this.output.print(";"); + } + } + + + // Prints date and time (plus semicolon, no line return); + public final synchronized void dateAndTimesc(){ + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + + this.output.print("This file was created at "); + this.output.print(tim); + this.output.print(" on "); + this.output.print(day); + this.output.print(";"); + } + + // Prints file title (title), date and time (plus semicolon, no line return); + public final synchronized void dateAndTimesc(String title){ + Date d = new Date(); + String day = DateFormat.getDateInstance().format(d); + String tim = DateFormat.getTimeInstance().format(d); + + this.output.print("This file, "+title+", was created at "); + this.output.print(tim); + this.output.print(" on "); + this.output.print(day); + this.output.print(";"); + } + + // Close file + public final synchronized void close(){ + this.output.close(); + } + + // Print a 2-D array of doubles to a text file, no file title provided + public static void printArrayToText(double[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 2-D array of doubles to a text file, file title provided + public static void printArrayToText(String title, double[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j]); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + // Print a 1-D array of doubles to a text file, no file title provided + public static void printArrayToText(double[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of doubles to a text file, file title provided + public static void printArrayToText(String title, double[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i]); + } + fo.println(); + fo.println("End of file."); + fo.close(); + } + + // Print a 2-D array of floats to a text file, no file title provided + public static void printArrayToText(float[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 2-D array of floats to a text file, file title provided + public static void printArrayToText(String title, float[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j]); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + + // Print a 1-D array of floats to a text file, no file title provided + public static void printArrayToText(float[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of float to a text file, file title provided + public static void printArrayToText(String title, float[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i]); + } + fo.println(); + fo.println("End of file."); + fo.close(); + } + + // Print a 2-D array of BigDecimal to a text file, no file title provided + public static void printArrayToText(BigDecimal[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 2-D array of BigDecimal to a text file, file title provided + public static void printArrayToText(String title, BigDecimal[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j].toString()); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + // Print a 2-D array of BigInteger to a text file, no file title provided + public static void printArrayToText(BigInteger[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + // Print a 2-D array of BigInteger to a text file, file title provided + public static void printArrayToText(String title, BigInteger[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j].toString()); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + + // Print a 1-D array of BigDecimal to a text file, no file title provided + public static void printArrayToText(BigDecimal[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of BigDecimal to a text file, file title provided + public static void printArrayToText(String title, BigDecimal[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i].toString()); + } + fo.println(); + fo.println("End of file."); + fo.close(); + } + + // Print a 1-D array of BigInteger to a text file, no file title provided + public static void printArrayToText(BigInteger[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of BigInteger to a text file, file title provided + public static void printArrayToText(String title, BigInteger[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i].toString()); + } + fo.println(); + fo.println("End of file."); + fo.close(); + } + + // Print a 2-D array of ints to a text file, no file title provided + public static void printArrayToText(int[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 2-D array of ints to a text file, file title provided + public static void printArrayToText(String title, int[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j]); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + + // Print a 1-D array of ints to a text file, no file title provided + public static void printArrayToText(int[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of int to a text file, file title provided + public static void printArrayToText(String title, int[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i]); + } + fo.println(); + fo.println("End of file."); + fo.close(); + } + + // Print a 2-D array of longs to a text file, no file title provided + public static void printArrayToText(long[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 2-D array of longs to a text file, file title provided + public static void printArrayToText(String title, long[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j]); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + + + + // Print a 1-D array of longs to a text file, no file title provided + public static void printArrayToText(long[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of long to a text file, file title provided + public static void printArrayToText(String title, long[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i]); + } + fo.println(); + fo.println("End of file."); + fo.close(); + } + + // Print a 2-D array of shorts to a text file, no file title provided + public static void printArrayToText(short[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 2-D array of shorts to a text file, file title provided + public static void printArrayToText(String title, short[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j]); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + // Print a 1-D array of shorts to a text file, no file title provided + public static void printArrayToText(short[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of short to a text file, file title provided + public static void printArrayToText(String title, short[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i]); + } + fo.println(); + fo.println("End of file."); + fo.close(); + } + + + // Print a 2-D array of bytes to a text file, no file title provided + public static void printArrayToText(byte[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 2-D array of bytes to a text file, file title provided + public static void printArrayToText(String title, byte[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j]); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + + // Print a 1-D array of bytes to a text file, no file title provided + public static void printArrayToText(byte[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of byte to a text file, file title provided + public static void printArrayToText(String title, byte[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i]); + } + fo.println(); + fo.println("End of file."); + fo.close(); + } + + + // Print a 2-D array of Strings to a text file, no file title provided + public static void printArrayToText(String[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 2-D array of Strings to a text file, file title provided + public static void printArrayToText(String title, String[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j]); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + + // Print a 1-D array of Strings to a text file, no file title provided + public static void printArrayToText(String[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of String to a text file, file title provided + public static void printArrayToText(String title, String[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i]); + } + fo.println(); + fo.println("End of file."); + fo.close(); + } + // Print a 2-D array of chars to a text file, no file title provided + public static void printArrayToText(char[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 2-D array of chars to a text file, file title provided + public static void printArrayToText(String title, char[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j]); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + + // Print a 1-D array of chars to a text file, no file title provided + public static void printArrayToText(char[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of char to a text file, file title provided + public static void printArrayToText(String title, char[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i]); + } + fo.println(); + fo.println("End of file."); + fo.close(); + } + // Print a 2-D array of booleans to a text file, no file title provided + public static void printArrayToText(boolean[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 2-D array of booleans to a text file, file title provided + public static void printArrayToText(String title, boolean[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j]); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + + // Print a 1-D array of booleans to a text file, no file title provided + public static void printArrayToText(boolean[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of boolean to a text file, file title provided + public static void printArrayToText(String title, boolean[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i]); + } + fo.println(); + fo.println("End of file."); + fo.close(); + } + + // Print a 2-D array of Complex to a text file, no file title provided + public static void printArrayToText(Complex[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + // Print a 2-D array of Complex to a text file, file title provided + public static void printArrayToText(String title, Complex[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j]); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + + // Print a 1-D array of Complex to a text file, no file title provided + public static void printArrayToText(Complex[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of Complex to a text file, file title provided + public static void printArrayToText(String title, Complex[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i]); + } + fo.println(); + fo.println("End of file."); + fo.close(); + } + + // Print a 2-D array of Phasor to a text file, no file title provided + public static void printArrayToText(Phasor[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + // Print a 2-D array of Phasor to a text file, file title provided + public static void printArrayToText(String title, Phasor[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j]); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + + // Print a 1-D array of Phasor to a text file, no file title provided + public static void printArrayToText(Phasor[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of Phasor to a text file, file title provided + public static void printArrayToText(String title, Phasor[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i]); + } + fo.println(); + fo.println("End of file."); + fo.close(); + } + + // Print a 2-D array of ErrorProp to a text file, no file title provided + public static void printArrayToText(ErrorProp[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 2-D array of ErrorProp to a text file, file title provided + public static void printArrayToText(String title, ErrorProp[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j]); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + + // Print a 1-D array of ErrorProp to a text file, no file title provided + public static void printArrayToText(ErrorProp[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of ErrorProp to a text file, file title provided + public static void printArrayToText(String title, ErrorProp[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i]); + } + fo.println(); + fo.println("End of file."); + fo.close(); + + } + + // Print a 2-D array of ComplexErrorProp to a text file, no file title provided + public static void printArrayToText(ComplexErrorProp[][] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 2-D array of ComplexErrorProp to a text file, file title provided + public static void printArrayToText(String title, ComplexErrorProp[][] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + int ncol = 0; + for(int i=0; i<nrow; i++){ + ncol=array[i].length; + for(int j=0; j<ncol; j++){ + fo.printtab(array[i][j]); + } + fo.println(); + } + fo.println("End of file."); + fo.close(); + } + + + // Print a 1-D array of ComplexErrorProp to a text file, no file title provided + public static void printArrayToText(ComplexErrorProp[] array){ + String title = "ArrayToText.txt"; + printArrayToText(title, array); + } + + + // Print a 1-D array of ComplexErrorProp to a text file, file title provided + public static void printArrayToText(String title, ComplexErrorProp[] array){ + FileOutput fo = new FileOutput(title, 'n'); + fo.dateAndTimeln(title); + int nrow = array.length; + for(int i=0; i<nrow; i++){ + fo.printtab(array[i]); + } + fo.println(); + fo.println("End of file."); + fo.close(); + } + + private static String setField(String ss, int f){ + char sp = ' '; + int n = ss.length(); + if(f>n){ + for(int i=n+1; i<=f; i++){ + ss=ss+sp; + } + } + return ss; + } +} diff --git a/src/main/java/flanagan/io/FileTypeFilter.java b/src/main/java/flanagan/io/FileTypeFilter.java new file mode 100755 index 0000000000000000000000000000000000000000..2cadf14032f71e5fbca781a730233b217b963fb7 --- /dev/null +++ b/src/main/java/flanagan/io/FileTypeFilter.java @@ -0,0 +1,282 @@ +/* SUN JAVA PROGRAM ExampleFileFilter retitled as FileTypeFilter + * + * UPDATED: June 2008 (generics and hashtable instantiation) + * + * Source j2sdk1.4.2\demo\jfc\FileChooserDemo\src\ExampleFileFilter.java + * + * SUN COPYRIGHT NOTICE: + * + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduct the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT + * BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT + * OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN + * IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that Software is not designed, licensed or intended for + * use in the design, construction, operation or maintenance of any nuclear + * facility. + */ + +/* + * @(#)ExampleFileFilter.java 1.14 03/01/23 + */ + +package flanagan.io; + +import java.io.File; +import java.util.Hashtable; +import java.util.Enumeration; +import javax.swing.*; +import javax.swing.filechooser.*; + +/** + * A convenience implementation of FileFilter that filters out + * all files except for those type extensions that it knows about. + * + * Extensions are of the type ".foo", which is typically found on + * Windows and Unix boxes, but not on Macinthosh. Case is ignored. + * + * Example - create a new filter that filerts out all files + * but gif and jpg image files: + * + * JFileChooser chooser = new JFileChooser(); + * ExampleFileFilter filter = new ExampleFileFilter( + * new String{"gif", "jpg"}, "JPEG & GIF Images") + * chooser.addChoosableFileFilter(filter); + * chooser.showOpenDialog(this); + * + * @version 1.14 01/23/03 + * @author Jeff Dinkins + */ +public class FileTypeFilter extends FileFilter { + + private static String TYPE_UNKNOWN = "Type Unknown"; + private static String HIDDEN_FILE = "Hidden File"; + + private Hashtable<String, FileTypeFilter> filters = null; + private String description = null; + private String fullDescription = null; + private boolean useExtensionsInDescription = true; + + + /** + * Creates a file filter. If no filters are added, then all + * files are accepted. + * + * @see #addExtension + */ + public FileTypeFilter() { + this.filters = new Hashtable<String, FileTypeFilter>(); + } + + /** + * Creates a file filter that accepts files with the given extension. + * Example: new FileTypeFilter("jpg"); + * + * @see #addExtension + */ + public FileTypeFilter(String extension) { + this(extension,null); + } + + /** + * Creates a file filter that accepts the given file type. + * Example: new FileTypeFilter("jpg", "JPEG Image Images"); + * + * Note that the "." before the extension is not needed. If + * provided, it will be ignored. + * + * @see #addExtension + */ + public FileTypeFilter(String extension, String description) { + this(); + if(extension!=null) addExtension(extension); + if(description!=null) setDescription(description); + } + + /** + * Creates a file filter from the given string array. + * Example: new FileTypeFilter(String {"gif", "jpg"}); + * + * Note that the "." before the extension is not needed adn + * will be ignored. + * + * @see #addExtension + */ + public FileTypeFilter(String[] filters) { + this(filters, null); + } + + /** + * Creates a file filter from the given string array and description. + * Example: new FileTypeFilter(String {"gif", "jpg"}, "Gif and JPG Images"); + * + * Note that the "." before the extension is not needed and will be ignored. + * + * @see #addExtension + */ + public FileTypeFilter(String[] filters, String description) { + this(); + for (int i = 0; i < filters.length; i++) { + // add filters one by one + addExtension(filters[i]); + } + if(description!=null) setDescription(description); + } + + /** + * Return true if this file should be shown in the directory pane, + * false if it shouldn't. + * + * Files that begin with "." are ignored. + * + * @see #getExtension + * @see FileFilter#accepts + */ + public boolean accept(File f) { + if(f != null) { + if(f.isDirectory()) { + return true; + } + String extension = getExtension(f); + if(extension != null && filters.get(getExtension(f)) != null) { + return true; + }; + } + return false; + } + + /** + * Return the extension portion of the file's name . + * + * @see #getExtension + * @see FileFilter#accept + */ + public String getExtension(File f) { + if(f != null) { + String filename = f.getName(); + int i = filename.lastIndexOf('.'); + if(i>0 && i<filename.length()-1) { + return filename.substring(i+1).toLowerCase(); + }; + } + return null; + } + + /** + * Adds a filetype "dot" extension to filter against. + * + * For example: the following code will create a filter that filters + * out all files except those that end in ".jpg" and ".tif": + * + * FileTypeFilter filter = new FileTypeFilter(); + * filter.addExtension("jpg"); + * filter.addExtension("tif"); + * + * Note that the "." before the extension is not needed and will be ignored. + */ + public void addExtension(String extension) { + if(filters == null) { + filters = new Hashtable<String, FileTypeFilter>(5); + } + filters.put(extension.toLowerCase(), this); + fullDescription = null; + } + + + /** + * Returns the human readable description of this filter. For + * example: "JPEG and GIF Image Files (*.jpg, *.gif)" + * + * @see setDescription + * @see setExtensionListInDescription + * @see isExtensionListInDescription + * @see FileFilter#getDescription + */ + public String getDescription() { + if(fullDescription == null) { + if(description == null || isExtensionListInDescription()) { + fullDescription = description==null ? "(" : description + " ("; + // build the description from the extension list + Enumeration extensions = filters.keys(); + if(extensions != null) { + fullDescription += "." + (String) extensions.nextElement(); + while (extensions.hasMoreElements()) { + fullDescription += ", ." + (String) extensions.nextElement(); + } + } + fullDescription += ")"; + } else { + fullDescription = description; + } + } + return fullDescription; + } + + /** + * Sets the human readable description of this filter. For + * example: filter.setDescription("Gif and JPG Images"); + * + * @see setDescription + * @see setExtensionListInDescription + * @see isExtensionListInDescription + */ + public void setDescription(String description) { + this.description = description; + fullDescription = null; + } + + /** + * Determines whether the extension list (.jpg, .gif, etc) should + * show up in the human readable description. + * + * Only relevent if a description was provided in the constructor + * or using setDescription(); + * + * @see getDescription + * @see setDescription + * @see isExtensionListInDescription + */ + public void setExtensionListInDescription(boolean b) { + useExtensionsInDescription = b; + fullDescription = null; + } + + /** + * Returns whether the extension list (.jpg, .gif, etc) should + * show up in the human readable description. + * + * Only relevent if a description was provided in the constructor + * or using setDescription(); + * + * @see getDescription + * @see setDescription + * @see setExtensionListInDescription + */ + public boolean isExtensionListInDescription() { + return useExtensionsInDescription; + } +} diff --git a/src/main/java/flanagan/io/KeyboardInput.java b/src/main/java/flanagan/io/KeyboardInput.java new file mode 100755 index 0000000000000000000000000000000000000000..cc52290a821a7e7e4ad3eba986e2e17e18aa9572 --- /dev/null +++ b/src/main/java/flanagan/io/KeyboardInput.java @@ -0,0 +1,1167 @@ +/* +* Class KeyboardInput +* +* Methods for entering +* double, float, BigDecimal, +* int, long, bigInteger, short, byte, +* String, char, boolean, +* Complex and Phasor variables +* from the key board +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: July 2002 +* REVISED: 26 July 2004, 26 June 2007, 21-23 July 2007 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/KeyboardInput.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) July 2002, July 2007 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.io; + +import java.io.*; +import java.math.*; + +import flanagan.complex.Complex; +import flanagan.circuits.Phasor; + +public class KeyboardInput +{ + // Data variable - buffered stream for the keyboard + private BufferedReader input = null; + + // Constructor + public KeyboardInput(){ + + this.input = new BufferedReader(new InputStreamReader(System.in)); + } + + // Reads a double from the keyboard with a prompt message + // No default option + // Input terminated by new line return + public final synchronized double readDouble(String mess){ + String line=""; + double d=0.0; + boolean finish = false; + + System.out.print(mess + " "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + d = Double.parseDouble(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid double\nRe-enter the number"); + } + } + + return d; + } + + // Reads a double from the keyboard with a prompt message and the return + // of a default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized double readDouble(String mess, double dflt){ + String line=""; + double d=0.0D; + boolean finish = false; + + System.out.print(mess + " [default value = " + dflt + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + d = dflt; + finish = true; + } + else{ + try{ + d = Double.parseDouble(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid double\nRe-enter the number"); + } + } + } + return d; + } + + // Reads a double from the keyboard + // No prompt message, No default option + // Input terminated by new line return + public final synchronized double readDouble(){ + String line=""; + double d=0.0D; + boolean finish = false; + + System.out.print(" "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + d = Double.parseDouble(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid double\nRe-enter the number"); + } + } + + return d; + } + + // Reads a float from the keyboard with a prompt message + // No default option + // Input terminated by new line return + public final synchronized float readFloat(String mess){ + String line=""; + float f=0.0F; + boolean finish = false; + + System.out.print(mess + " "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + f = Float.parseFloat(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid float\nRe-enter the number"); + } + } + + return f; + } + + // Reads a float from the keyboard with a prompt message and the return + // of a default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized float readFloat(String mess, float dflt){ + String line=""; + float f=0.0F; + boolean finish = false; + + System.out.print(mess + " [default value = " + dflt + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + f = dflt; + finish = true; + } + else{ + try{ + f = Float.parseFloat(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid float\nRe-enter the number"); + } + } + } + return f; + } + + // Reads a float from the keyboard + // No prompt message, No default option + // Input terminated by new line return + public final synchronized float readFloat(){ + String line=""; + float f=0.0F; + boolean finish = false; + + System.out.print(" "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + f = Float.parseFloat(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid float\nRe-enter the number"); + } + } + + return f; + } + + // Reads a BigDecimal from the keyboard with a prompt message + // No default option + // Input terminated by new line return + public final synchronized BigDecimal readBigDecimal(String mess){ + String line=""; + BigDecimal big = null; + boolean finish = false; + + System.out.print(mess + " "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + big = new BigDecimal(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid BigDecimal\nRe-enter the number"); + } + } + + return big; + } + + + // Reads a BigDecimal from the keyboard with a prompt message and the return + // of a BigDecimal default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized BigDecimal readBigDecimal(String mess, BigDecimal dflt){ + String line=""; + BigDecimal big = null; + boolean finish = false; + + System.out.print(mess + " [default value = " + dflt.toString() + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + big = dflt; + finish = true; + } + else{ + try{ + big = new BigDecimal(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid BigDecimal\nRe-enter the number"); + } + } + } + return big; + } + + // Reads a BigDecimal from the keyboard with a prompt message and the return + // of a double default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized BigDecimal readBigDecimal(String mess, double dflt){ + String line=""; + BigDecimal big = null; + boolean finish = false; + Double dfltD = new Double(dflt); + String dfltM = dfltD.toString(); + + System.out.print(mess + " [default value = " + dfltM + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + big = new BigDecimal(dfltM); + finish = true; + } + else{ + try{ + big = new BigDecimal(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid BigDecimal\nRe-enter the number"); + } + } + } + return big; + } + + + // Reads a BigDecimal from the keyboard with a prompt message and the return + // of a float default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized BigDecimal readBigDecimal(String mess, float dflt){ + String line=""; + BigDecimal big = null; + boolean finish = false; + Float dfltF = new Float(dflt); + String dfltM = dfltF.toString(); + + System.out.print(mess + " [default value = " + dfltM + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + big = new BigDecimal(dfltM); + finish = true; + } + else{ + try{ + big = new BigDecimal(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid BigDecimal\nRe-enter the number"); + } + } + } + return big; + } + + + // Reads a BigDecimal from the keyboard with a prompt message and the return + // of a long default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized BigDecimal readBigDecimal(String mess, long dflt){ + String line=""; + BigDecimal big = null; + boolean finish = false; + Long dfltL = new Long(dflt); + String dfltM = dfltL.toString(); + + System.out.print(mess + " [default value = " + dfltM + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + big = new BigDecimal(dfltM); + finish = true; + } + else{ + try{ + big = new BigDecimal(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid BigDecimal\nRe-enter the number"); + } + } + } + return big; + } + + + // Reads a BigDecimal from the keyboard with a prompt message and the return + // of a int default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized BigDecimal readBigDecimal(String mess, int dflt){ + String line=""; + BigDecimal big = null; + boolean finish = false; + Integer dfltI = new Integer(dflt); + String dfltM = dfltI.toString(); + + System.out.print(mess + " [default value = " + dfltM + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + big = new BigDecimal(dfltM); + finish = true; + } + else{ + try{ + big = new BigDecimal(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid BigDecimal\nRe-enter the number"); + } + } + } + return big; + } + + + // Reads a BigDecimal from the keyboard with a prompt message and the return + // of a String default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized BigDecimal readBigDecimal(String mess, String dflt){ + String line=""; + BigDecimal big = null; + boolean finish = false; + + System.out.print(mess + " [default value = " + dflt + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + big = new BigDecimal(dflt); + finish = true; + } + else{ + try{ + big = new BigDecimal(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid BigDecimal\nRe-enter the number"); + } + } + } + return big; + } + + // Reads a BigDecimal from the keyboard + // No prompt message, No default option + // Input terminated by new line return + public final synchronized BigDecimal readBigDecimal(){ + String line=""; + BigDecimal big = null; + boolean finish = false; + + System.out.print(" "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + big = new BigDecimal(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid BigDecimal\nRe-enter the number"); + } + } + + return big; + } + + // Reads an int (integer) from the keyboard with a prompt message + // No default option + // Input terminated by new line return + public final synchronized int readInt(String mess){ + String line=""; + int ii = 0; + boolean finish = false; + + System.out.print(mess + " "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + ii = Integer.parseInt(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid int\nRe-enter the number"); + } + } + + return ii; + } + + // Reads an int (integer) from the keyboard with a prompt message and the return + // of a default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized int readInt(String mess, int dflt){ + String line=""; + int ii = 0; + boolean finish = false; + + System.out.print(mess + " [default value = " + dflt + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + ii = dflt; + finish = true; + } + else{ + try{ + ii = Integer.parseInt(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid int\nRe-enter the number"); + } + } + } + return ii; + } + + // Reads an int (integer) from the keyboard + // No prompt message, No default option + // Input terminated by new line return + public final synchronized int readInt(){ + String line=""; + int ii = 0; + boolean finish = false; + + System.out.print(" "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + ii = Integer.parseInt(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid int\nRe-enter the number"); + } + } + + return ii; + } + + // Reads a long integer from the keyboard with a prompt message + // No default option + // Input terminated by new line return + public final synchronized long readLong(String mess){ + String line=""; + long ll = 0L; + boolean finish = false; + + System.out.print(mess + " "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + ll = Long.parseLong(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid long\nRe-enter the number"); + } + } + + return ll; + } + + // Reads a long integer from the keyboard with a prompt message and the return + // of a default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized long readLong(String mess, long dflt){ + String line=""; + long ll = 0L; + boolean finish = false; + + System.out.print(mess + " [default value = " + dflt + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + ll = dflt; + finish = true; + } + else{ + try{ + ll = Long.parseLong(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid long\nRe-enter the number"); + } + } + } + return ll; + } + + // Reads a long integer from the keyboard + // No prompt message, No default option + // Input terminated by new line return + public final synchronized long readLong(){ + String line=""; + long ll = 0L; + boolean finish = false; + + System.out.print(" "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + ll = Long.parseLong(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid long\nRe-enter the number"); + } + } + + return ll; + } + + // Reads a BigInteger from the keyboard with a prompt message + // No default option + // Input terminated by new line return + public final synchronized BigInteger readBigInteger(String mess){ + String line=""; + BigInteger big = null; + boolean finish = false; + + System.out.print(mess + " "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + big = new BigInteger(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid BigInteger\nRe-enter the number"); + } + } + + return big; + } + + + // Reads a BigInteger from the keyboard with a prompt message and the return + // of a BigInteger default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized BigInteger readBigInteger(String mess, BigInteger dflt){ + String line=""; + BigInteger big = null; + boolean finish = false; + + System.out.print(mess + " [default value = " + dflt.toString() + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + big = dflt; + finish = true; + } + else{ + try{ + big = new BigInteger(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid BigInteger\nRe-enter the number"); + } + } + } + return big; + } + + // Reads a BigInteger from the keyboard with a prompt message and the return + // of a long default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized BigInteger readBigInteger(String mess, long dflt){ + String line=""; + BigInteger big = null; + boolean finish = false; + Long dfltL = new Long(dflt); + String dfltM = dfltL.toString(); + + System.out.print(mess + " [default value = " + dfltM + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + big = new BigInteger(dfltM); + finish = true; + } + else{ + try{ + big = new BigInteger(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid BigInteger\nRe-enter the number"); + } + } + } + return big; + } + + + // Reads a BigInteger from the keyboard with a prompt message and the return + // of a int default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized BigInteger readBigInteger(String mess, int dflt){ + String line=""; + BigInteger big = null; + boolean finish = false; + Integer dfltI = new Integer(dflt); + String dfltM = dfltI.toString(); + + System.out.print(mess + " [default value = " + dfltM + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + big = new BigInteger(dfltM); + finish = true; + } + else{ + try{ + big = new BigInteger(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid BigInteger\nRe-enter the number"); + } + } + } + return big; + } + + + // Reads a BigInteger from the keyboard with a prompt message and the return + // of a String default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized BigInteger readBigInteger(String mess, String dflt){ + String line=""; + BigInteger big = null; + boolean finish = false; + + System.out.print(mess + " [default value = " + dflt + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + big = new BigInteger(dflt); + finish = true; + } + else{ + try{ + big = new BigInteger(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid BigInteger\nRe-enter the number"); + } + } + } + return big; + } + + // Reads a BigInteger from the keyboard + // No prompt message, No default option + // Input terminated by new line return + public final synchronized BigInteger readBigInteger(){ + String line=""; + BigInteger big = null; + boolean finish = false; + + System.out.print(" "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + big = new BigInteger(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid BigInteger\nRe-enter the number"); + } + } + + return big; + } + + + // Reads a short integer from the keyboard with a prompt message + // No default option + // Input terminated by new line return + public final synchronized short readShort(String mess){ + String line=""; + short ss = 0; + boolean finish = false; + + System.out.print(mess + " "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + ss = Short.parseShort(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid short\nRe-enter the number"); + } + } + + return ss; + } + + // Reads a short integer from the keyboard with a prompt message and the return + // of a default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized short readShort(String mess, short dflt){ + String line=""; + short ss = 0; + boolean finish = false; + + System.out.print(mess + " [default value = " + dflt + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + ss = dflt; + finish = true; + } + else{ + try{ + ss = Short.parseShort(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid short\nRe-enter the number"); + } + } + } + return ss; + } + + // Reads a short integer from the keyboard + // No prompt message, No default option + // Input terminated by new line return + public final synchronized short readShort(){ + String line=""; + short ss = 0; + boolean finish = false; + + System.out.print(" "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + ss = Short.parseShort(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid short\nRe-enter the number"); + } + } + + return ss; + } + + // Reads a byte integer from the keyboard with a prompt message + // No default option + // Input terminated by new line return + public final synchronized byte readByte(String mess){ + String line=""; + byte bb = 0; + boolean finish = false; + + System.out.print(mess + " "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + bb = Byte.parseByte(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid byte\nRe-enter the number"); + } + } + + return bb; + } + + // Reads a byte integer from the keyboard with a prompt message and the return + // of a default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized byte readByte(String mess, byte dflt){ + String line=""; + byte bb = 0; + boolean finish = false; + + System.out.print(mess + " [default value = " + dflt + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.length()==0){ + bb = dflt; + finish = true; + } + else{ + try{ + bb = Byte.parseByte(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid byte\nRe-enter the number"); + } + } + } + return bb; + } + + // Reads a byte integer from the keyboard + // No prompt message, No default option + // Input terminated by new line return + public final synchronized byte readByte(){ + String line=""; + byte bb = 0; + boolean finish = false; + + System.out.print(" "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + try{ + bb = Byte.parseByte(line.trim()); + finish=true; + }catch(NumberFormatException e){ + System.out.println("You did not enter a valid byte\nRe-enter the number"); + } + } + + return bb; + } + + // Reads a long integer from the keyboard with a prompt message + // No default option + // Input terminated by new line return + public final synchronized char readChar(String mess){ + String line=""; + char ch=' '; + boolean finish = false; + + System.out.print(mess + " "); + System.out.flush(); + + line = this.enterLine(); + line = line.trim(); + ch = line.charAt(0); + + return ch; + } + + // Reads a long integer from the keyboard with a prompt message and the return + // of a default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized char readChar(String mess, char dflt){ + String line=""; + char ch=' '; + boolean finish = false; + + System.out.print(mess + " [default value = " + dflt + "] "); + System.out.flush(); + + line = this.enterLine(); + line = line.trim(); + ch = line.charAt(0); + + return ch; + } + + // Reads a char from the keyboard + // No prompt message, No default option + // Input terminated by new line return + public final synchronized char readChar(){ + String line = ""; + char ch = ' '; + boolean finish = false; + + System.out.print(" "); + System.out.flush(); + + line = this.enterLine(); + line = line.trim(); + ch = line.charAt(0); + + return ch; + } + + // Reads a boolean from the keyboard with a prompt message + // No default option + // Input terminated by new line return + public final synchronized boolean readBoolean(String mess){ + String line=""; + boolean b=false; + boolean finish = false; + + System.out.print(mess + " "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.trim().equals("true") || line.trim().equals("TRUE")){ + b = true; + finish = true; + } + else{ + if(line.trim().equals("false") || line.trim().equals("FALSE")){ + b = false; + finish=true; + } + else{ + System.out.println("You did not enter a valid boolean\nRe-enter the number"); + } + } + } + return b; + } + + // Reads a boolean from the keyboard with a prompt message and the return + // of a default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized boolean readBoolean(String mess, boolean dflt){ + String line=""; + boolean b=false; + boolean finish = false; + System.out.print(mess + " [default value = " + dflt + "] "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.trim().equals("true") || line.trim().equals("TRUE")){ + b = true; + finish = true; + } + else{ + if(line.trim().equals("false") || line.trim().equals("FALSE")){ + b = false; + finish=true; + } + else{ + System.out.println("You did not enter a valid boolean\nRe-enter the number"); + } + } + } + return b; + } + + // Reads a boolean from the keyboard + // No prompt message, No default option + // Input terminated by new line return + public final synchronized boolean readBoolean(){ + String line=""; + boolean b=false; + boolean finish = false; + + System.out.print(" "); + System.out.flush(); + + while(!finish){ + line = this.enterLine(); + if(line.trim().equals("true") || line.trim().equals("TRUE")){ + b = true; + finish = true; + } + else{ + if(line.trim().equals("false") || line.trim().equals("FALSE")){ + b = false; + finish=true; + } + else{ + System.out.println("You did not enter a valid boolean\nRe-enter the number"); + } + } + } + return b; + } + + // Reads a Complex from the keyboard with a prompt message + // No default option + // Input terminated by new line return + public final synchronized Complex readComplex(String mess){ + return Complex.readComplex(mess); + } + + // Reads a Complex from the keyboard with a prompt message and Stringdefault value option + // Input terminated by new line return + public final synchronized Complex readComplex(String mess, String dflt){ + return Complex.readComplex(mess, dflt); + } + + // Reads a Complex from the keyboard with a prompt message and Complexdefault value option + // Input terminated by new line return + public final synchronized Complex readComplex(String mess, Complex dflt){ + return Complex.readComplex(mess, dflt); + } + + + // Reads a Complex from the keyboard + // No prompt + // No default option + // Input terminated by new line return + public final synchronized Complex readComplex(){ + return Complex.readComplex(); + } + + // Reads a Phasor from the keyboard with a prompt message + // No default option + // Input terminated by new line return + public final synchronized Phasor readPhasor(String mess){ + return Phasor.readPhasor(mess); + } + + // Reads a Phasor from the keyboard with a prompt message and Stringdefault value option + // Input terminated by new line return + public final synchronized Phasor readPhasor(String mess, String dflt){ + return Phasor.readPhasor(mess, dflt); + } + + // Reads a Phasor from the keyboard with a prompt message and Phasordefault value option + // Input terminated by new line return + public final synchronized Phasor readPhasor(String mess, Phasor dflt){ + return Phasor.readPhasor(mess, dflt); + } + + + // Reads a Phasor from the keyboard + // No prompt + // No default option + // Input terminated by new line return + public final synchronized Phasor readPhasor(){ + return Phasor.readPhasor(); + } + + // Reads a line from the keyboard with a prompt message + // No default option + // Input terminated by new line return + public final synchronized String readLine(String mess){ + System.out.print(mess + " "); + System.out.flush(); + + return this.enterLine(); + } + + // Reads a line from the keyboard with a prompt message and the return + // of a default option if the return key alone is pressed + // Input terminated by new line return + public final synchronized String readLine(String mess, String dflt){ + String line = ""; + System.out.print(mess + " [default option = " + dflt + "] "); + System.out.flush(); + + line = this.enterLine(); + if(line.length()==0)line = dflt; + + return line; + } + + // Reads a line from the keyboard + // No prompt message, no default option + // Input terminated by new line return + private final synchronized String readLine(){ + + return this.enterLine(); + } + + // Enters a line from the keyboard + // Private method called by public methods + private final synchronized String enterLine(){ + String line = ""; + + try{ + line = input.readLine(); + }catch(java.io.IOException e){ + System.out.println(e); + } + + return line; + } +} diff --git a/src/main/java/flanagan/io/MultipleFilesChooser.java b/src/main/java/flanagan/io/MultipleFilesChooser.java new file mode 100755 index 0000000000000000000000000000000000000000..8c69085e92a4561b6fd3384a0ac3637f03e9bd61 --- /dev/null +++ b/src/main/java/flanagan/io/MultipleFilesChooser.java @@ -0,0 +1,185 @@ +/* +* Class MultipleFilesChooser +* +* Methods for selecting and opening for reading several files through a dialogue box +* All folders and files may be displayed or a specific extension, e.g. txt, +* may be set (the extension filter uses the class FileTypeFilter which is +* the SUN JAVA filter, ExampleFileFilter, retitled) +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 28 November 2005 +* AMENDED: 11 August 2006 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/MultipleFilesChooser.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) November 2005 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.io; + +import javax.swing.*; +import java.io.*; +import java.util.*; +import javax.swing.filechooser.*; +import flanagan.io.FileInput; + +public class MultipleFilesChooser{ + + private String[] fileNames = null; // file names selected + private String[] pathNames = null; // path names selected + private String[] dirNames = null; // directory path of files selected + private String[] stemNames = null; // file names minus the extension + + private FileInput[] fileObjects = null; // instances of the FileInput object corresponding to each File selected + private int nFiles = 0; // Number of files selected + private String path = null; // path to directory from which the files are selected + // e.g. "C:\\Java\\flanagan + // default (path=null) - home directory + private String extn = null; // file type extension of files to be displayed + // default (extn=null) - all file types displayed + // constructor + // opens home directory + public MultipleFilesChooser(){ + } + + // constructor + // opens directory given by path + public MultipleFilesChooser(String path){ + this.path = path; + } + + // use JFileChooser to select the required file + // uses default prompt ("Select File") + public FileInput[] selectFiles(){ + return this.selectFiles("Select File"); + } + + // use a JFileChooser to select the required file + // display user supplied prompt + public FileInput[] selectFiles(String prompt){ + JFileChooser chooser = new JFileChooser(this.path); + chooser.setMultiSelectionEnabled(true); + if(this.extn!=null){ + // Add filter + FileTypeFilter f = new FileTypeFilter(); + f.addExtension(extn); + f.setDescription(extn + " files"); + chooser.setFileFilter(f); + } + else{ + // enable all files displayed option + chooser.setAcceptAllFileFilterUsed(true); + } + + chooser.setDialogTitle(prompt); + chooser.showOpenDialog(null); + File[] files = chooser.getSelectedFiles(); + this.nFiles = files.length; + this.fileObjects = new FileInput[nFiles]; + this.fileNames = new String[nFiles]; + this.stemNames = new String[nFiles]; + this.pathNames = new String[nFiles]; + this.dirNames = new String[nFiles]; + + for(int i=0; i<nFiles; i++){ + this.fileNames[i] = files[i].getName(); + this.pathNames[i] = files[i].toString(); + this.dirNames[i] = (files[i].getParentFile()).toString(); + this.fileObjects[i] = new FileInput(this.pathNames[i]); + int posDot = this.fileNames[i].indexOf('.'); + if(posDot==-1){ + this.stemNames[i] = this.fileNames[i]; + } + else{ + this.stemNames[i] = this.fileNames[i].substring(0, posDot); + } + } + + return this.fileObjects; + } + + // set path + public void setPath(String path){ + this.path = path; + } + + // get path + public String getPath(){ + return this.path; + } + + // set extension - display files with extension extn + public void setExtension(String extn){ + this.extn = extn; + } + + // display all file extensions + public void setAllExtensions(){ + this.extn = null; + } + + // get extension + public String getExtension(){ + return this.extn; + } + + // get number of files selected + public int getNumberOfFiles(){ + return this.nFiles; + } + + // get file names + public String[] getFileNames(){ + return this.fileNames; + } + + // get file names without the extensions + public String[] getStemNames(){ + return this.stemNames; + } + + // get file paths + public String[] getPathNames(){ + return this.pathNames; + } + + // get file directories + public String[] getDirPaths(){ + return this.dirNames; + } + + // close all files that have been opened + public final synchronized void close(){ + for(int i=0; i<this.nFiles; i++){ + this.fileObjects[i].close(); + } + } + + // Displays dialogue box asking if you wish to exit program + // Answering yes end program + public static final synchronized void endProgram(){ + + int ans = JOptionPane.showConfirmDialog(null, "Do you wish to end the program", "End Program", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if(ans==0){ + System.exit(0); + } + else{ + JOptionPane.showMessageDialog(null, "Now you must press the appropriate escape key/s, e.g. Ctrl C, to exit this program"); + } + } +} diff --git a/src/main/java/flanagan/io/PrintToScreen.java b/src/main/java/flanagan/io/PrintToScreen.java new file mode 100755 index 0000000000000000000000000000000000000000..7f0612ec12568276281c766f2f0fd816aa87f286 --- /dev/null +++ b/src/main/java/flanagan/io/PrintToScreen.java @@ -0,0 +1,701 @@ +/* +* Class PrintToScreen +* +* USAGE: Methods for writing one and two dimensional arrays to the sceen +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 13 April 2008 (Most methods taken from existing classes to make a separate print to screen class) +* AMENDED: 11 August 2008, 14 September 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/PrintToScreen.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.io; + +import java.math.*; + +import flanagan.math.Fmath; +import flanagan.math.ArrayMaths; +import flanagan.complex.Complex; +import flanagan.circuits.Phasor; + +public class PrintToScreen{ + + // 1D ARRAYS + + // print an array of doubles to screen + // No line returns except at the end + public static void print(double[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of doubles to screen with truncation + // No line returns except at the end + public static void print(double[] aa, int trunc){ + for(int i=0; i<aa.length; i++){ + System.out.print(Fmath.truncate(aa[i], trunc)+" "); + } + System.out.println(); + } + + // print an array of doubles to screen + // with line returns + public static void println(double[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of doubles to screen with truncation + // with line returns + public static void println(double[] aa, int trunc){ + for(int i=0; i<aa.length; i++){ + System.out.println(Fmath.truncate(aa[i], trunc)+" "); + } + } + + // print an array of floats to screen + // No line returns except at the end + public static void print(float[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of floats to screen with truncation + // No line returns except at the end + public static void print(float[] aa, int trunc){ + for(int i=0; i<aa.length; i++){ + System.out.print(Fmath.truncate(aa[i], trunc)+" "); + } + System.out.println(); + } + + // print an array of floats to screen + // with line returns + public static void println(float[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of floats to screen with truncation + // with line returns + public static void println(float[] aa, int trunc){ + for(int i=0; i<aa.length; i++){ + System.out.println(Fmath.truncate(aa[i], trunc)+" "); + } + } + + // print an array of ints to screen + // No line returns except at the end + public static void print(int[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of ints to screen + // with line returns + public static void println(int[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of longs to screen + // No line returns except at the end + public static void print(long[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of longs to screen + // with line returns + public static void println(long[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of shorts to screen + // No line returns except at the end + public static void print(short[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of shorts to screen + // with line returns + public static void println(short[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of char to screen + // No line returns except at the end + public static void print(char[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of char to screen + // with line returns + public static void println(char[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + + // print an array of bytes to screen + // No line returns except at the end + public static void print(byte[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of bytes to screen + // with line returns + public static void println(byte[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + + // print an array of Doubles to screen + // No line returns except at the end + public static void print(Double[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of Doubles to screen with truncation + // No line returns except at the end + public static void print(Double[] aa, int trunc){ + ArrayMaths am = new ArrayMaths(aa); + am = am.truncate(trunc); + Double[] aaa = am.array_as_Double(); + for(int i=0; i<aa.length; i++){ + System.out.print(aaa[i]+" "); + } + System.out.println(); + } + + // print an array of Doubles to screen + // with line returns + public static void println(Double[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of Doubles to screen with truncation + // with line returns + public static void println(Double[] aa, int trunc){ + ArrayMaths am = new ArrayMaths(aa); + am = am.truncate(trunc); + Double[] aaa = am.array_as_Double(); + for(int i=0; i<aa.length; i++){ + System.out.println(aaa[i]+" "); + } + } + + // print an array of Floats to screen + // No line returns except at the end + public static void print(Float[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of Floats to screen + // No line returns except at the end + public static void print(Float[] aa, int trunc){ + ArrayMaths am = new ArrayMaths(aa); + am = am.truncate(trunc); + Float[] aaa = am.array_as_Float(); + for(int i=0; i<aa.length; i++){ + System.out.print(aaa[i]+" "); + } + System.out.println(); + } + + // print an array of Floats to screen + // with line returns + public static void println(Float[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of Floats to screen with truncation + // with line returns + public static void println(Float[] aa, int trunc){ + ArrayMaths am = new ArrayMaths(aa); + am = am.truncate(trunc); + Float[] aaa = am.array_as_Float(); + for(int i=0; i<aa.length; i++){ + System.out.println(aaa[i]+" "); + } + } + + // print an array of Integers to screen + // No line returns except at the end + public static void print(Integer[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of Integers to screen + // with line returns + public static void println(Integer[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of Longs to screen + // No line returns except at the end + public static void print(Long[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of Longs to screen + // with line returns + public static void println(Long[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of Shorts to screen + // No line returns except at the end + public static void print(Short[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of Shorts to screen + // with line returns + public static void println(Short[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of Character to screen + // No line returns except at the end + public static void print(Character[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of Character to screen + // with line returns + public static void println(Character[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + + // print an array of Bytes to screen + // No line returns except at the end + public static void print(Byte[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of Bytes to screen + // with line returns + public static void println(Byte[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of String to screen + // No line returns except at the end + public static void print(String[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of Strings to screen + // with line returns + public static void println(String[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of Complex to screen + // No line returns except at the end + public static void print(Complex[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of Complex to screen with truncation + // No line returns except at the end + public static void print(Complex[] aa, int trunc){ + for(int i=0; i<aa.length; i++){ + System.out.print(Complex.truncate(aa[i], trunc)+" "); + } + System.out.println(); + } + + // print an array of Complex to screen + // with line returns + public static void println(Complex[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of Complex to screen with truncation + // with line returns + public static void println(Complex[] aa, int trunc){ + for(int i=0; i<aa.length; i++){ + System.out.println(Complex.truncate(aa[i], trunc)+" "); + } + } + + + // print an array of Phasor to screen + // No line returns except at the end + public static void print(Phasor[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of Phasor to screen with truncation + // No line returns except at the end + public static void print(Phasor[] aa, int trunc){ + for(int i=0; i<aa.length; i++){ + System.out.print(Phasor.truncate(aa[i], trunc)+" "); + } + System.out.println(); + } + + // print an array of Phasor to screen + // with line returns + public static void println(Phasor[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of Phasor to screen with truncation + // with line returns + public static void println(Phasor[] aa, int trunc){ + for(int i=0; i<aa.length; i++){ + System.out.println(Phasor.truncate(aa[i], trunc)+" "); + } + } + + + // print an array of BigDecimal to screen + // No line returns except at the end + public static void print(BigDecimal[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of BigDecimal to screen + // with line returns + public static void println(BigDecimal[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of BigInteger to screen + // No line returns except at the end + public static void print(BigInteger[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of BigInteger to screen + // with line returns + public static void println(BigInteger[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of boolean to screen + // No line returns except at the end + public static void print(boolean[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of boolean to screen + // with line returns + public static void println(boolean[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + + // 2D ARRAYS + + // print a 2D array of doubles to screen + public static void print(double[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of doubles to screen with truncation + public static void print(double[][] aa, int trunc){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i], trunc); + } + } + + // print a 2D array of floats to screen + public static void print(float[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of floats to screen with truncation + public static void print(float[][] aa, int trunc){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i], trunc); + } + } + + // print a 2D array of ints to screen + public static void print(int[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of longs to screen + public static void print(long[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + // print a 2D array of chars to screen + public static void print(char[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of bytes to screen + public static void print(byte[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of shorts to screen + public static void print(short[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of Doubles to screen + public static void print(Double[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of Doubles to screen with truncation + public static void print(Double[][] aa, int trunc){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i], trunc); + } + } + + // print a 2D array of Floats to screen + public static void print(Float[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of Floats to screen with truncation + public static void print(Float[][] aa, int trunc){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i], trunc); + } + } + + + // print a 2D array of Integers to screen + public static void print(Integer[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of Longs to screen + public static void print(Long[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + // print a 2D array of Characters to screen + public static void print(Character[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of Bytes to screen + public static void print(Byte[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of Shorts to screen + public static void print(Short[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of Strings to screen + public static void print(String[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of Complex to screen + public static void print(Complex[][] aa){ + for(int i=0; i<aa.length; i++){ + Complex.print(aa[i]); + } + } + + // print a 2D array of Complex to screen with truncation + public static void print(Complex[][] aa, int trunc){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i], trunc); + } + } + + // print a 2D array of Phasor to screen + public static void print(Phasor[][] aa){ + for(int i=0; i<aa.length; i++){ + Phasor.print(aa[i]); + } + } + + // print a 2D array of Phasor to screen + public static void print(Phasor[][] aa, int trunc){ + + Phasor[][] aam = aa.clone(); + for(int i=0; i<aam.length; i++){ + for(int j=0; j<aam[i].length; j++){ + aam[i][j] = Phasor.truncate(aam[i][j], trunc); + } + } + for(int i=0; i<aa.length; i++){ + Phasor.print(aam[i]); + } + } + + // print a 2D array of BigDecimal to screen + public static void print(BigDecimal[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of BigInteger to screen + public static void print(BigInteger[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } + + // print a 2D array of boolean to screen + public static void print(boolean[][] aa){ + for(int i=0; i<aa.length; i++){ + PrintToScreen.print(aa[i]); + } + } +} + + + diff --git a/src/main/java/flanagan/math/ArrayMaths.java b/src/main/java/flanagan/math/ArrayMaths.java new file mode 100755 index 0000000000000000000000000000000000000000..72e6b75a5bedd62e151a674b00d459b2fa8c259e --- /dev/null +++ b/src/main/java/flanagan/math/ArrayMaths.java @@ -0,0 +1,15101 @@ +/* +* Class ArrayMaths +* +* USAGE: One dimensional arrays: mathematical manipulations and inter-conversions +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: April 2008 +* AMENDED: 22-30 May 2008, 4 June 2008, 27-28 June 2007, 2-4 July 2008, +* 8 July 2008, 25 July 2008, 4 September 2008, 13 December 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* http://www.ee.ucl.ac.uk/~mflanaga/java/ArrayMaths.html +* +* Copyright (c) 2008 +* +* PERMISSION TO COPY: +* +* Redistributions of this source code, or parts of, must retain the above +* copyright notice, this list of conditions and the following disclaimer. +* +* Redistribution in binary form of all or parts of this class, must reproduce +* the above copyright, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the distribution. +* +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all +* copies and associated documentation or publications. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.math; + + +import java.math.*; +import java.util.Vector; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import flanagan.complex.Complex; +import flanagan.complex.ComplexMatrix; +import flanagan.circuits.Phasor; +import flanagan.circuits.PhasorMatrix; +import flanagan.math.Conv; +import flanagan.analysis.Stat; +import flanagan.io.PrintToScreen; +import flanagan.plot.*; + +public class ArrayMaths{ + + protected ArrayList<Object> array = null; // internal array + + protected int length = 0; // array length + protected int type = -1; // 0 double, 1 Double, 2 float, 3 Float, 4 long, 5 Long, 6 int, 7 Integer, 8 short, 9 Short, 10 byte, 11 Byte + // 12 BigDecimal, 13 BigInteger, 14 Complex, 15 Phasor, 16 char, 17 Character, 18 String + protected int[] originalTypes = null; // list of entered types in the array + + protected String[] typeName = {"double", "Double", "float", "Float", "long", "Long", "int", "Integer", "short", "Short", "byte", "Byte", "BigDecimal", "BigInteger", "Complex", "Phasor", "char", "Character", "String"}; + + protected ArrayList<Object> summ = new ArrayList<Object>(1); // sum of all elements + protected ArrayList<Object> productt = new ArrayList<Object>(1); // product of all elements + + protected int[] sortedIndices = null; // sorted indices + + protected ArrayList<Object> minmax = new ArrayList<Object>(2); // element at 0 - maximum value + // element at 1 - minimum value + protected int maxIndex = -1; // index of the maximum value array element + protected int minIndex = -1; // index of the minimum value array element + + protected boolean sumDone = false; // = true whem array sum has been found + protected boolean productDone = false; // = true whem array product has been found + + protected boolean sumlongToDouble = false; // = true whem long has been converted to Double to avoid overflow in summation + protected boolean productlongToDouble = false; // = true whem long has been converted to Double to avoid overflow in multiplication + + protected boolean suppressMessages = false; // = true when suppress 'possible loss of precision' messages has been set + + + // HashMap for 'arithmetic integer' recognition nmethod + protected static final Map<Object,Object> integers = new HashMap<Object,Object>(); + static{ + integers.put(Integer.class, BigDecimal.valueOf(Integer.MAX_VALUE)); + integers.put(Long.class, BigDecimal.valueOf(Long.MAX_VALUE)); + integers.put(Byte.class, BigDecimal.valueOf(Byte.MAX_VALUE)); + integers.put(Short.class, BigDecimal.valueOf(Short.MAX_VALUE)); + integers.put(BigInteger.class, BigDecimal.valueOf(-1)); + } + + // CONSTRUCTORS + protected ArrayMaths(){ + this.array = new ArrayList<Object>(); + } + + public ArrayMaths(double[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 0; + for(int i=0; i<this.length; i++)this.array.add(new Double(array[i])); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(Double[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 1; + for(int i=0; i<this.length; i++)this.array.add(array[i]); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(long[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 4; + for(int i=0; i<this.length; i++)this.array.add(new Long(array[i])); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(Long[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 5; + for(int i=0; i<this.length; i++)this.array.add(array[i]); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(float[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 2; + for(int i=0; i<this.length; i++)this.array.add(new Float(array[i])); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(Float[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 3; + for(int i=0; i<this.length; i++)this.array.add(array[i]); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(int[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 6; + for(int i=0; i<this.length; i++)this.array.add(new Integer(array[i])); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(Integer[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 7; + for(int i=0; i<this.length; i++)this.array.add(array[i]); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(short[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 8; + for(int i=0; i<this.length; i++)this.array.add(new Short(array[i])); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(Short[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 9; + for(int i=0; i<this.length; i++)this.array.add(array[i]); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(byte[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 10; + for(int i=0; i<this.length; i++)this.array.add(new Byte(array[i])); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(Byte[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 11; + for(int i=0; i<this.length; i++)this.array.add(array[i]); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(BigDecimal[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 12; + for(int i=0; i<this.length; i++)this.array.add(array[i]); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(BigInteger[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 13; + for(int i=0; i<this.length; i++)this.array.add(array[i]); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(Complex[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 14; + for(int i=0; i<this.length; i++)this.array.add(array[i]); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + } + + public ArrayMaths(Phasor[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 15; + for(int i=0; i<this.length; i++)this.array.add(array[i]); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + } + + public ArrayMaths(char[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 16; + for(int i=0; i<this.length; i++)this.array.add(new Character(array[i])); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(Character[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 17; + for(int i=0; i<this.length; i++)this.array.add(array[i]); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(String[] array){ + this.length = array.length; + this.array = new ArrayList<Object>(this.length); + this.type = 18; + for(int i=0; i<this.length; i++)this.array.add(array[i]); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + } + + public ArrayMaths(Object[] array){ + this.length = array.length; + this.originalTypes = new int[this.length]; + ArrayList<Object> arrayl = new ArrayList<Object>(this.length); + for(int i=0; i<this.length; i++)arrayl.add(array[i]); + ArrayMaths am = new ArrayMaths(arrayl); + this.array = am.getArray_as_ArrayList(); + this.minmax = am.minmax; + this.minIndex = am.minIndex; + this.maxIndex = am.maxIndex; + this.originalTypes = am.originalTypes; + } + + public ArrayMaths(Stat arrayst){ + this.array = arrayst.getArray_as_ArrayList(); + this.length = this.array.size(); + this.type = arrayst.typeIndex(); + this.originalTypes = new int[this.length]; + for(int i=0; i<this.length; i++)this.originalTypes[i] = this.type; + this.minmax(); + } + + public ArrayMaths(Vector<Object> arrayv){ + this.length = arrayv.size(); + this.originalTypes = new int[this.length]; + this.array = new ArrayList<Object>(this.length); + + for(int i=0; i<this.length; i++){ + this.originalTypes[i] = -1; + if(arrayv.elementAt(i) instanceof Double)this.originalTypes[i] = 1; + if(arrayv.elementAt(i) instanceof Float)this.originalTypes[i] = 3; + if(arrayv.elementAt(i) instanceof Long)this.originalTypes[i] = 5; + if(arrayv.elementAt(i) instanceof Integer)this.originalTypes[i] = 7; + if(arrayv.elementAt(i) instanceof Short)this.originalTypes[i] = 9; + if(arrayv.elementAt(i) instanceof Byte)this.originalTypes[i] =11; + if(arrayv.elementAt(i) instanceof BigDecimal)this.originalTypes[i] = 12; + if(arrayv.elementAt(i) instanceof BigInteger)this.originalTypes[i] = 13; + if(arrayv.elementAt(i) instanceof Complex)this.originalTypes[i] = 14; + if(arrayv.elementAt(i) instanceof Phasor)this.originalTypes[i] = 15; + if(arrayv.elementAt(i) instanceof Character)this.originalTypes[i] = 17; + if(arrayv.elementAt(i) instanceof String)this.originalTypes[i] = 18; + if(this.originalTypes[i]==-1)throw new IllegalArgumentException("Object at " + i + " not recognised as one allowed by this class"); + } + + int testType = -1; + for(int i=0; i<this.length; i++)if(this.originalTypes[i]==18)testType = 0; + for(int i=0; i<this.length; i++)if(this.originalTypes[i]==14)testType = 1; + if(testType==-1)for(int i=0; i<this.length; i++)if(this.originalTypes[i]==15)testType = 2; + if(testType==-1)for(int i=0; i<this.length; i++)if(this.originalTypes[i]==12)testType = 3; + if(testType==-1)for(int i=0; i<this.length; i++)if(this.originalTypes[i]==13)testType = 4; + if(testType==4)for(int i=0; i<this.length; i++)if(this.originalTypes[i]<=3)testType = 3; + if(testType==-1)for(int i=0; i<this.length; i++)if(this.originalTypes[i]<=3)testType = 5; + if(testType==-1)for(int i=0; i<this.length; i++)if(this.originalTypes[i]>3 && this.originalTypes[i]<12)testType = 6; + if(testType==-1)for(int i=0; i<this.length; i++)if(this.originalTypes[i]==17)testType = 7; + if(testType==-1)throw new IllegalArgumentException("It should not be possible to reach this exception - main Object type not identified"); + switch(testType){ + case 0: this.type = 18; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 1: Double hold1= (Double)arrayv.elementAt(i); + this.array.add(hold1.toString()); + break; + case 3: Float hold3 = (Float)arrayv.elementAt(i); + this.array.add(hold3.toString()); + break; + case 5: Long hold5 = (Long)arrayv.elementAt(i); + this.array.add(hold5.toString()); + break; + case 7: Integer hold7 = (Integer)arrayv.elementAt(i); + this.array.add(hold7.toString()); + break; + case 9: Short hold9 = (Short)arrayv.elementAt(i); + this.array.add(hold9.toString()); + break; + case 11: Byte hold11 = (Byte)arrayv.elementAt(i); + this.array.add(hold11.toString()); + break; + case 12: BigDecimal hold12 = (BigDecimal)arrayv.elementAt(i); + this.array.add(hold12.toString()); + break; + case 13: BigInteger hold13 = (BigInteger)arrayv.elementAt(i); + this.array.add(hold13.toString()); + break; + case 14: Complex hold14 = (Complex)arrayv.elementAt(i); + this.array.add(hold14.toString()); + break; + case 15: Phasor hold15 = (Phasor)arrayv.elementAt(i); + this.array.add(hold15.toString()); + break; + case 17: Character hold17 = (Character)arrayv.elementAt(i); + this.array.add(hold17.toString()); + break; + case 18: String hold18 = (String)arrayv.elementAt(i); + this.array.add(hold18); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + case 1: this.type = 14; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 1: Double hold1= (Double)arrayv.elementAt(i); + this.array.add(new Complex(hold1.doubleValue())); + break; + case 3: Float hold3 = (Float)arrayv.elementAt(i); + this.array.add(new Complex(hold3.doubleValue())); + break; + case 5: Long hold5 = (Long)arrayv.elementAt(i); + this.array.add(new Complex(hold5.doubleValue())); + break; + case 7: Integer hold7 = (Integer)arrayv.elementAt(i); + this.array.add(new Complex(hold7.doubleValue())); + break; + case 9: Short hold9 = (Short)arrayv.elementAt(i); + this.array.add(new Complex(hold9.doubleValue())); + break; + case 11: Byte hold11 = (Byte)arrayv.elementAt(i); + this.array.add(new Complex(hold11.doubleValue())); + break; + case 12: BigDecimal hold12 = (BigDecimal)arrayv.elementAt(i); + this.array.add(new Complex(hold12.doubleValue())); + break; + case 13: BigInteger hold13 = (BigInteger)arrayv.elementAt(i); + this.array.add(new Complex(hold13.doubleValue())); + break; + case 14: Complex hold14 = (Complex)arrayv.elementAt(i); + this.array.add(hold14); + break; + case 15: Phasor hold15 = (Phasor)arrayv.elementAt(i); + this.array.add(Conv.convert_Phasor_to_Complex(hold15)); + break; + case 17: Character hold17 = (Character)arrayv.elementAt(i); + this.array.add(new Complex((double)((int)hold17.charValue()))); + break; + case 18: String hold18 = (String)arrayv.elementAt(i); + this.array.add(new Complex(Double.parseDouble(hold18))); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + case 2: this.type = 15; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 1: Double hold1= (Double)arrayv.elementAt(i); + this.array.add(new Phasor(hold1.doubleValue())); + break; + case 3: Float hold3 = (Float)arrayv.elementAt(i); + this.array.add(new Phasor(hold3.doubleValue())); + break; + case 5: Long hold5 = (Long)arrayv.elementAt(i); + this.array.add(new Phasor(hold5.doubleValue())); + break; + case 7: Integer hold7 = (Integer)arrayv.elementAt(i); + this.array.add(new Phasor(hold7.doubleValue())); + break; + case 9: Short hold9 = (Short)arrayv.elementAt(i); + this.array.add(new Phasor(hold9.doubleValue())); + break; + case 11: Byte hold11 = (Byte)arrayv.elementAt(i); + this.array.add(new Phasor(hold11.doubleValue())); + break; + case 12: BigDecimal hold12 = (BigDecimal)arrayv.elementAt(i); + this.array.add(new Phasor(hold12.doubleValue())); + break; + case 13: BigInteger hold13 = (BigInteger)arrayv.elementAt(i); + this.array.add(new Phasor(hold13.doubleValue())); + break; + case 14: Complex hold14 = (Complex)arrayv.elementAt(i); + this.array.add(Conv.convert_Complex_to_Phasor(hold14)); + break; + case 15: Phasor hold15 = (Phasor)arrayv.elementAt(i); + this.array.add(hold15); + break; + case 17: Character hold17 = (Character)arrayv.elementAt(i); + this.array.add(new Phasor((double)((int)hold17.charValue()))); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + case 3: this.type = 12; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 1: Double hold1 = (Double)arrayv.elementAt(i); + this.array.add(Conv.convert_Double_to_BigDecimal(hold1)); + break; + case 3: Float hold3 = (Float)arrayv.elementAt(i); + this.array.add(Conv.convert_Float_to_BigDecimal(hold3)); + break; + case 5: Long hold5 = (Long)arrayv.elementAt(i); + this.array.add(Conv.convert_Long_to_BigDecimal(hold5)); + break; + case 7: Integer hold7 = (Integer)arrayv.elementAt(i); + this.array.add(Conv.convert_Integer_to_BigDecimal(hold7)); + break; + case 9: Short hold9 = (Short)arrayv.elementAt(i); + this.array.add(Conv.convert_Short_to_BigDecimal(hold9)); + break; + case 11: Byte hold11 = (Byte)arrayv.elementAt(i); + this.array.add(Conv.convert_Byte_to_BigDecimal(hold11)); + break; + case 12: BigDecimal hold12 = (BigDecimal)arrayv.elementAt(i); + this.array.add(hold12); + break; + case 13: BigInteger hold13 = (BigInteger)arrayv.elementAt(i); + this.array.add(Conv.convert_BigInteger_to_BigDecimal(hold13)); + break; + case 17: Character hold17 = (Character)arrayv.elementAt(i); + this.array.add(new BigDecimal(hold17.toString())); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + case 4: this.type = 13; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 1: Double hold1 = (Double)arrayv.elementAt(i); + this.array.add(Conv.convert_Double_to_BigInteger(hold1)); + break; + case 3: Float hold3 = (Float)arrayv.elementAt(i); + this.array.add(Conv.convert_Float_to_BigInteger(hold3)); + break; + case 5: Long hold5 = (Long)arrayv.elementAt(i); + this.array.add(Conv.convert_Long_to_BigInteger(hold5)); + break; + case 7: Integer hold7 = (Integer)arrayv.elementAt(i); + this.array.add(Conv.convert_Integer_to_BigInteger(hold7)); + break; + case 9: Short hold9 = (Short)arrayv.elementAt(i); + this.array.add(Conv.convert_Short_to_BigInteger(hold9)); + break; + case 11: Byte hold11 = (Byte)arrayv.elementAt(i); + this.array.add(Conv.convert_Byte_to_BigInteger(hold11)); + break; + case 12: BigDecimal hold12 = (BigDecimal)arrayv.elementAt(i); + this.array.add(Conv.convert_BigDecimal_to_BigInteger(hold12)); + break; + case 13: BigInteger hold13 = (BigInteger)arrayv.elementAt(i); + this.array.add(hold13); + break; + case 17: Character hold17 = (Character)arrayv.elementAt(i); + this.array.add(new BigInteger(hold17.toString())); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + case 5: this.type = 1; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 1: Double hold1 = (Double)arrayv.elementAt(i); + this.array.add(hold1); + break; + case 3: Float hold3 = (Float)arrayv.elementAt(i); + this.array.add(Conv.convert_Float_to_Double(hold3)); + break; + case 5: Long hold5 = (Long)arrayv.elementAt(i); + this.array.add(Conv.convert_Long_to_Double(hold5)); + break; + case 7: Integer hold7 = (Integer)arrayv.elementAt(i); + this.array.add(Conv.convert_Integer_to_Double(hold7)); + break; + case 9: Short hold9 = (Short)arrayv.elementAt(i); + this.array.add(Conv.convert_Short_to_Double(hold9)); + break; + case 11: Byte hold11 = (Byte)arrayv.elementAt(i); + this.array.add(Conv.convert_Byte_to_Double(hold11)); + break; + case 17: Character hold17 = (Character)arrayv.elementAt(i); + this.array.add(new Double(Double.parseDouble(hold17.toString()))); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + case 6: this.type = 7; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 5: Long hold5 = (Long)arrayv.elementAt(i); + this.array.add(hold5); + break; + case 7: Integer hold7 = (Integer)arrayv.elementAt(i); + this.array.add(Conv.convert_Integer_to_Long(hold7)); + break; + case 9: Short hold9 = (Short)arrayv.elementAt(i); + this.array.add(Conv.convert_Short_to_Long(hold9)); + break; + case 11: Byte hold11 = (Byte)arrayv.elementAt(i); + this.array.add(Conv.convert_Byte_to_Long(hold11)); + break; + case 17: Character hold17 = (Character)arrayv.elementAt(i); + this.array.add(new Long((long)((int)hold17.charValue()))); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + case 7: this.type = 7; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 17: Character hold17 = (Character)arrayv.elementAt(i); + this.array.add(hold17); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + default: throw new IllegalArgumentException("Dominant array data type not identified by this method"); + } + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: this.minmax(); + } + } + + + public ArrayMaths(ArrayList<Object> arrayl){ + this.length = arrayl.size(); + this.originalTypes = new int[this.length]; + this.array = new ArrayList<Object>(this.length); + + for(int i=0; i<this.length; i++){ + this.originalTypes[i] = -1; + if(arrayl.get(i) instanceof Double)this.originalTypes[i] = 1; + if(arrayl.get(i) instanceof Float)this.originalTypes[i] = 3; + if(arrayl.get(i) instanceof Long)this.originalTypes[i] = 5; + if(arrayl.get(i) instanceof Integer)this.originalTypes[i] = 7; + if(arrayl.get(i) instanceof Short)this.originalTypes[i] = 9; + if(arrayl.get(i) instanceof Byte)this.originalTypes[i] =11; + if(arrayl.get(i) instanceof BigDecimal)this.originalTypes[i] = 12; + if(arrayl.get(i) instanceof BigInteger)this.originalTypes[i] = 13; + if(arrayl.get(i) instanceof Complex)this.originalTypes[i] = 14; + if(arrayl.get(i) instanceof Phasor)this.originalTypes[i] = 15; + if(arrayl.get(i) instanceof Character)this.originalTypes[i] = 17; + if(arrayl.get(i) instanceof String)this.originalTypes[i] = 18; + if(this.originalTypes[i]==-1)throw new IllegalArgumentException("Object at " + i + " not recognised as one allowed by this class"); + } + + int testType = -1; + for(int i=0; i<this.length; i++)if(this.originalTypes[i]==18)testType = 0; + for(int i=0; i<this.length; i++)if(this.originalTypes[i]==14)testType = 1; + if(testType==-1)for(int i=0; i<this.length; i++)if(this.originalTypes[i]==15)testType = 2; + if(testType==-1)for(int i=0; i<this.length; i++)if(this.originalTypes[i]==12)testType = 3; + if(testType==-1)for(int i=0; i<this.length; i++)if(this.originalTypes[i]==13)testType = 4; + if(testType==4)for(int i=0; i<this.length; i++)if(this.originalTypes[i]<=3)testType = 3; + if(testType==-1)for(int i=0; i<this.length; i++)if(this.originalTypes[i]<=3)testType = 5; + if(testType==-1)for(int i=0; i<this.length; i++)if(this.originalTypes[i]>3 && this.originalTypes[i]<12)testType = 6; + if(testType==-1)for(int i=0; i<this.length; i++)if(this.originalTypes[i]==17)testType = 7; + if(testType==-1)throw new IllegalArgumentException("It should not be possible to reach this exception - main Object type not identified"); + switch(testType){ + case 0: this.type = 18; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 1: Double hold1= (Double)arrayl.get(i); + this.array.add(hold1.toString()); + break; + case 3: Float hold3 = (Float)arrayl.get(i); + this.array.add(hold3.toString()); + break; + case 5: Long hold5 = (Long)arrayl.get(i); + this.array.add(hold5.toString()); + break; + case 7: Integer hold7 = (Integer)arrayl.get(i); + this.array.add(hold7.toString()); + break; + case 9: Short hold9 = (Short)arrayl.get(i); + this.array.add(hold9.toString()); + break; + case 11: Byte hold11 = (Byte)arrayl.get(i); + this.array.add(hold11.toString()); + break; + case 12: BigDecimal hold12 = (BigDecimal)arrayl.get(i); + this.array.add(hold12.toString()); + break; + case 13: BigInteger hold13 = (BigInteger)arrayl.get(i); + this.array.add(hold13.toString()); + break; + case 14: Complex hold14 = (Complex)arrayl.get(i); + this.array.add(hold14.toString()); + break; + case 15: Phasor hold15 = (Phasor)arrayl.get(i); + this.array.add(hold15.toString()); + break; + case 17: Character hold17 = (Character)arrayl.get(i); + this.array.add(hold17.toString()); + break; + case 18: String hold18 = (String)arrayl.get(i); + this.array.add(hold18); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + case 1: this.type = 14; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 1: Double hold1= (Double)arrayl.get(i); + this.array.add(new Complex(hold1.doubleValue())); + break; + case 3: Float hold3 = (Float)arrayl.get(i); + this.array.add(new Complex(hold3.doubleValue())); + break; + case 5: Long hold5 = (Long)arrayl.get(i); + this.array.add(new Complex(hold5.doubleValue())); + break; + case 7: Integer hold7 = (Integer)arrayl.get(i); + this.array.add(new Complex(hold7.doubleValue())); + break; + case 9: Short hold9 = (Short)arrayl.get(i); + this.array.add(new Complex(hold9.doubleValue())); + break; + case 11: Byte hold11 = (Byte)arrayl.get(i); + this.array.add(new Complex(hold11.doubleValue())); + break; + case 12: BigDecimal hold12 = (BigDecimal)arrayl.get(i); + this.array.add(new Complex(hold12.doubleValue())); + break; + case 13: BigInteger hold13 = (BigInteger)arrayl.get(i); + this.array.add(new Complex(hold13.doubleValue())); + break; + case 14: Complex hold14 = (Complex)arrayl.get(i); + this.array.add(hold14); + break; + case 15: Phasor hold15 = (Phasor)arrayl.get(i); + this.array.add(Conv.convert_Phasor_to_Complex(hold15)); + break; + case 17: Character hold17 = (Character)arrayl.get(i); + this.array.add(new Complex((double)((int)hold17.charValue()))); + break; + case 18: String hold18 = (String)arrayl.get(i); + this.array.add(new Complex(Double.parseDouble(hold18))); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + case 2: this.type = 15; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 1: Double hold1= (Double)arrayl.get(i); + this.array.add(new Phasor(hold1.doubleValue())); + break; + case 3: Float hold3 = (Float)arrayl.get(i); + this.array.add(new Phasor(hold3.doubleValue())); + break; + case 5: Long hold5 = (Long)arrayl.get(i); + this.array.add(new Phasor(hold5.doubleValue())); + break; + case 7: Integer hold7 = (Integer)arrayl.get(i); + this.array.add(new Phasor(hold7.doubleValue())); + break; + case 9: Short hold9 = (Short)arrayl.get(i); + this.array.add(new Phasor(hold9.doubleValue())); + break; + case 11: Byte hold11 = (Byte)arrayl.get(i); + this.array.add(new Phasor(hold11.doubleValue())); + break; + case 12: BigDecimal hold12 = (BigDecimal)arrayl.get(i); + this.array.add(new Phasor(hold12.doubleValue())); + break; + case 13: BigInteger hold13 = (BigInteger)arrayl.get(i); + this.array.add(new Phasor(hold13.doubleValue())); + break; + case 14: Complex hold14 = (Complex)arrayl.get(i); + this.array.add(Conv.convert_Complex_to_Phasor(hold14)); + break; + case 15: Phasor hold15 = (Phasor)arrayl.get(i); + this.array.add(hold15); + break; + case 17: Character hold17 = (Character)arrayl.get(i); + this.array.add(new Phasor((double)((int)hold17.charValue()))); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + case 3: this.type = 12; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 1: Double hold1 = (Double)arrayl.get(i); + this.array.add(Conv.convert_Double_to_BigDecimal(hold1)); + break; + case 3: Float hold3 = (Float)arrayl.get(i); + this.array.add(Conv.convert_Float_to_BigDecimal(hold3)); + break; + case 5: Long hold5 = (Long)arrayl.get(i); + this.array.add(Conv.convert_Long_to_BigDecimal(hold5)); + break; + case 7: Integer hold7 = (Integer)arrayl.get(i); + this.array.add(Conv.convert_Integer_to_BigDecimal(hold7)); + break; + case 9: Short hold9 = (Short)arrayl.get(i); + this.array.add(Conv.convert_Short_to_BigDecimal(hold9)); + break; + case 11: Byte hold11 = (Byte)arrayl.get(i); + this.array.add(Conv.convert_Byte_to_BigDecimal(hold11)); + break; + case 12: BigDecimal hold12 = (BigDecimal)arrayl.get(i); + this.array.add(hold12); + break; + case 13: BigInteger hold13 = (BigInteger)arrayl.get(i); + this.array.add(Conv.convert_BigInteger_to_BigDecimal(hold13)); + break; + case 17: Character hold17 = (Character)arrayl.get(i); + this.array.add(new BigDecimal(hold17.toString())); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + case 4: this.type = 13; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 1: Double hold1 = (Double)arrayl.get(i); + this.array.add(Conv.convert_Double_to_BigInteger(hold1)); + break; + case 3: Float hold3 = (Float)arrayl.get(i); + this.array.add(Conv.convert_Float_to_BigInteger(hold3)); + break; + case 5: Long hold5 = (Long)arrayl.get(i); + this.array.add(Conv.convert_Long_to_BigInteger(hold5)); + break; + case 7: Integer hold7 = (Integer)arrayl.get(i); + this.array.add(Conv.convert_Integer_to_BigInteger(hold7)); + break; + case 9: Short hold9 = (Short)arrayl.get(i); + this.array.add(Conv.convert_Short_to_BigInteger(hold9)); + break; + case 11: Byte hold11 = (Byte)arrayl.get(i); + this.array.add(Conv.convert_Byte_to_BigInteger(hold11)); + break; + case 12: BigDecimal hold12 = (BigDecimal)arrayl.get(i); + this.array.add(Conv.convert_BigDecimal_to_BigInteger(hold12)); + break; + case 13: BigInteger hold13 = (BigInteger)arrayl.get(i); + this.array.add(hold13); + break; + case 17: Character hold17 = (Character)arrayl.get(i); + this.array.add(new BigInteger(hold17.toString())); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + case 5: this.type = 1; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 1: Double hold1 = (Double)arrayl.get(i); + this.array.add(hold1); + break; + case 3: Float hold3 = (Float)arrayl.get(i); + this.array.add(Conv.convert_Float_to_Double(hold3)); + break; + case 5: Long hold5 = (Long)arrayl.get(i); + this.array.add(Conv.convert_Long_to_Double(hold5)); + break; + case 7: Integer hold7 = (Integer)arrayl.get(i); + this.array.add(Conv.convert_Integer_to_Double(hold7)); + break; + case 9: Short hold9 = (Short)arrayl.get(i); + this.array.add(Conv.convert_Short_to_Double(hold9)); + break; + case 11: Byte hold11 = (Byte)arrayl.get(i); + this.array.add(Conv.convert_Byte_to_Double(hold11)); + break; + case 17: Character hold17 = (Character)arrayl.get(i); + this.array.add(new Double(Double.parseDouble(hold17.toString()))); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + case 6: this.type = 7; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 5: Long hold5 = (Long)arrayl.get(i); + this.array.add(hold5); + break; + case 7: Integer hold7 = (Integer)arrayl.get(i); + this.array.add(Conv.convert_Integer_to_Long(hold7)); + break; + case 9: Short hold9 = (Short)arrayl.get(i); + this.array.add(Conv.convert_Short_to_Long(hold9)); + break; + case 11: Byte hold11 = (Byte)arrayl.get(i); + this.array.add(Conv.convert_Byte_to_Long(hold11)); + break; + case 17: Character hold17 = (Character)arrayl.get(i); + this.array.add(new Long((long)((int)hold17.charValue()))); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + case 7: this.type = 7; + for(int i=0; i<this.length; i++){ + switch(this.originalTypes[i]){ + case 17: Character hold17 = (Character)arrayl.get(i); + this.array.add(hold17); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + break; + default: throw new IllegalArgumentException("Dominant array data type not identified by this method"); + } + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: this.minmax(); + } + } + + // ARRAY LENGTH + // retuns array length + public int length(){ + return this.length; + } + + + // ARRAY TYPE + // retuns array type as the index: + // 0 double, 1 Double, 2 float, 3 Float, 4 long, 5 Long, 6 int, 7 Integer, 8 short, 9 Short, 10 byte, 11 Byte + // 12 BigDecimal, 13 BigInteger, 14 Complex, 15 Phasor, 16 char, 17 Character or 18 String + public int typeIndex(){ + return this.type; + } + + // retuns array type as the name: + // 0 double, 1 Double, 2 float, 3 Float, 4 long, 5 Long, 6 int, 7 Integer, 8 short, 9 Short, 10 byte, 11 Byte + // 12 BigDecimal, 13 BigInteger, 14 Complex, 15 Phasor, 16 char, 17 Character or 18 String + public String arrayType(){ + return (this.typeName[this.type] + "[]"); + } + + // retuns original array types, before conversion to common type if array entered as mixed types, as the names: + // 0 double, 1 Double, 2 float, 3 Float, 4 long, 5 Long, 6 int, 7 Integer, 8 short, 9 Short, 10 byte, 11 Byte + // 12 BigDecimal, 13 BigInteger, 14 Complex, 15 Phasor, 16 char, 17 Character or 18 String + public String[] originalArrayTypes(){ + String[] ss = new String[this.length]; + for(int i=0; i<this.length; i++)ss[i] = this.typeName[this.originalTypes[i]]; + return ss; + } + + // DEEP COPY + // Copy to a new instance of ArrayMaths + public ArrayMaths copy(){ + ArrayMaths am = new ArrayMaths(); + + am.length = this.length; + am.maxIndex = this.maxIndex; + am.minIndex = this.minIndex; + am.sumDone = this.sumDone; + am.productDone = this.productDone; + am.sumlongToDouble = this.sumlongToDouble; + am.productlongToDouble = this.productlongToDouble; + am.type = this.type; + if(this.originalTypes==null){ + am.originalTypes = null; + } + else{ + am.originalTypes = this.originalTypes.clone(); + } + if(this.sortedIndices==null){ + am.sortedIndices = null; + } + else{ + am.sortedIndices = this.sortedIndices.clone(); + } + am.suppressMessages = this.suppressMessages; + am.minmax = new ArrayList<Object>(); + if(this.minmax.size()!=0){ + switch(this.type){ + case 0: + case 1: double dd = ((Double)this.minmax.get(0)).doubleValue(); + am.minmax.add(new Double(dd)); + dd = ((Double)this.minmax.get(1)).doubleValue(); + am.minmax.add(new Double(dd)); + break; + case 4: + case 5: long ll= ((Long)this.minmax.get(0)).longValue(); + am.minmax.add(new Double(ll)); + ll = ((Long)this.minmax.get(1)).longValue(); + am.minmax.add(new Long(ll)); + break; + case 2: + case 3: float ff = ((Float)this.minmax.get(0)).floatValue(); + am.minmax.add(new Double(ff)); + ff = ((Float)this.minmax.get(1)).floatValue(); + am.minmax.add(new Double(ff)); + break; + case 6: + case 7: int ii = ((Integer)this.minmax.get(0)).intValue(); + am.minmax.add(new Integer(ii)); + ii = ((Double)this.minmax.get(1)).intValue(); + am.minmax.add(new Integer(ii)); + break; + case 8: + case 9: short ss = ((Short)this.minmax.get(0)).shortValue(); + am.minmax.add(new Short(ss)); + ss = ((Double)this.minmax.get(1)).shortValue(); + am.minmax.add(new Short((ss))); + break; + case 10: + case 11: byte bb = ((Byte)this.minmax.get(0)).byteValue(); + am.minmax.add(new Byte(bb)); + ss = ((Byte)this.minmax.get(1)).byteValue(); + am.minmax.add(new Byte((bb))); + break; + case 12: BigDecimal bd = (BigDecimal)this.minmax.get(0); + am.minmax.add(bd); + bd = (BigDecimal)this.minmax.get(1); + am.minmax.add(bd); + bd = null; + break; + case 13: BigInteger bi = (BigInteger)this.minmax.get(0); + am.minmax.add(bi); + bi = (BigInteger)this.minmax.get(1); + am.minmax.add(bi); + bi = null; + break; + case 16: + case 17: int iii = ((Integer)this.minmax.get(0)).intValue(); + am.minmax.add(new Integer(iii)); + iii = ((Double)this.minmax.get(1)).intValue(); + am.minmax.add(new Integer(iii)); + break; + } + } + + am.summ = new ArrayList<Object>(); + if(this.summ.size()!=0){ + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: double dd = ((Double)summ.get(0)).doubleValue(); + am.summ.add(new Double(dd)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + double dd2 = ((Double)summ.get(0)).doubleValue(); + am.summ.add(new Double(dd2)); + } + else{ + long ll = ((Long)summ.get(0)).longValue(); + am.summ.add(new Long(ll)); + } + break; + case 12: BigDecimal bd = (BigDecimal)summ.get(0); + am.summ.add(bd); + break; + case 13: BigInteger bi = (BigInteger)summ.get(0); + am.summ.add(bi); + break; + case 14: Complex cc = (Complex)summ.get(0); + am.summ.add(cc); + break; + case 15: Phasor pp = (Phasor)summ.get(0); + am.summ.add(pp); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + + am.productt = new ArrayList<Object>(); + if(this.productt.size()!=0){ + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: double dd = ((Double)productt.get(0)).doubleValue(); + am.productt.add(new Double(dd)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + double dd2 = ((Double)productt.get(0)).doubleValue(); + am.productt.add(new Double(dd2)); + } + else{ + long ll = ((Long)productt.get(0)).longValue(); + am.productt.add(new Long(ll)); + } + break; + case 12: BigDecimal bd = (BigDecimal)productt.get(0); + am.productt.add(bd); + break; + case 13: BigInteger bi = (BigInteger)productt.get(0); + am.productt.add(bi); + break; + case 14: Complex cc = (Complex)productt.get(0); + am.productt.add(cc); + break; + case 15: Phasor pp = (Phasor)productt.get(0); + am.productt.add(pp); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + + + switch(this.type){ + case 0: + case 1: double[] dd = this.getArray_as_double().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i])); + break; + case 2: + case 3: float[] ff = this.getArray_as_float().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Float(ff[i])); + break; + case 4: + case 5: long[] ll = this.getArray_as_long().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i])); + break; + case 6: + case 7: int[] ii = this.getArray_as_int().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Integer(ii[i])); + break; + case 8: + case 9: short[] ss = this.getArray_as_short().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Short(ss[i])); + break; + case 10: + case 11: byte[] bb = this.getArray_as_byte().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Byte(bb[i])); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal().clone(); + for(int i=0; i<this.length; i++)am.array.add(bd[i]); + break; + case 13: BigInteger[] bi = this.getArray_as_BigInteger().clone(); + for(int i=0; i<this.length; i++)am.array.add(bi[i]); + break; + case 14: Complex[] ccc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(ccc[i].copy()); + break; + case 15: Phasor[] ppp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(ppp[i].copy()); + break; + case 16: + case 17: char[] cc = this.getArray_as_char().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Character(cc[i])); + break; + case 18: String[] sss = this.getArray_as_String().clone(); + for(int i=0; i<this.length; i++)am.array.add(sss[i]); + break; + } + + return am; + } + + // Copy to a new instance of Stat + public Stat statCopy(){ + + Stat am = new Stat(); + am.length = this.length; + am.maxIndex = this.maxIndex; + am.minIndex = this.minIndex; + am.sumDone = this.sumDone; + am.productDone = this.productDone; + am.sumlongToDouble = this.sumlongToDouble; + am.productlongToDouble = this.productlongToDouble; + am.type = this.type; + if(this.originalTypes==null){ + am.originalTypes = null; + } + else{ + am.originalTypes = this.originalTypes.clone(); + } + if(this.sortedIndices==null){ + am.sortedIndices = null; + } + else{ + am.sortedIndices = this.sortedIndices.clone(); + } + am.suppressMessages = this.suppressMessages; + am.minmax = new ArrayList<Object>(); + if(this.minmax.size()!=0){ + switch(this.type){ + case 0: + case 1: double dd = ((Double)this.minmax.get(0)).doubleValue(); + am.minmax.add(new Double(dd)); + dd = ((Double)this.minmax.get(1)).doubleValue(); + am.minmax.add(new Double(dd)); + break; + case 4: + case 5: long ll= ((Long)this.minmax.get(0)).longValue(); + am.minmax.add(new Double(ll)); + ll = ((Long)this.minmax.get(1)).longValue(); + am.minmax.add(new Long(ll)); + break; + case 2: + case 3: float ff = ((Float)this.minmax.get(0)).floatValue(); + am.minmax.add(new Double(ff)); + ff = ((Float)this.minmax.get(1)).floatValue(); + am.minmax.add(new Double(ff)); + break; + case 6: + case 7: int ii = ((Integer)this.minmax.get(0)).intValue(); + am.minmax.add(new Integer(ii)); + ii = ((Double)this.minmax.get(1)).intValue(); + am.minmax.add(new Integer(ii)); + break; + case 8: + case 9: short ss = ((Short)this.minmax.get(0)).shortValue(); + am.minmax.add(new Short(ss)); + ss = ((Double)this.minmax.get(1)).shortValue(); + am.minmax.add(new Short((ss))); + break; + case 10: + case 11: byte bb = ((Byte)this.minmax.get(0)).byteValue(); + am.minmax.add(new Byte(bb)); + ss = ((Byte)this.minmax.get(1)).byteValue(); + am.minmax.add(new Byte((bb))); + break; + case 12: BigDecimal bd = (BigDecimal)this.minmax.get(0); + am.minmax.add(bd); + bd = (BigDecimal)this.minmax.get(1); + am.minmax.add(bd); + bd = null; + break; + case 13: BigInteger bi = (BigInteger)this.minmax.get(0); + am.minmax.add(bi); + bi = (BigInteger)this.minmax.get(1); + am.minmax.add(bi); + bi = null; + break; + case 16: + case 17: int iii = ((Integer)this.minmax.get(0)).intValue(); + am.minmax.add(new Integer(iii)); + iii = ((Double)this.minmax.get(1)).intValue(); + am.minmax.add(new Integer(iii)); + break; + } + } + + am.summ = new ArrayList<Object>(); + if(this.summ.size()!=0){ + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: double dd = ((Double)summ.get(0)).doubleValue(); + am.summ.add(new Double(dd)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + double dd2 = ((Double)summ.get(0)).doubleValue(); + am.summ.add(new Double(dd2)); + } + else{ + long ll = ((Long)summ.get(0)).longValue(); + am.summ.add(new Long(ll)); + } + break; + case 12: BigDecimal bd = (BigDecimal)summ.get(0); + am.summ.add(bd); + break; + case 13: BigInteger bi = (BigInteger)summ.get(0); + am.summ.add(bi); + break; + case 14: Complex cc = (Complex)summ.get(0); + am.summ.add(cc); + break; + case 15: Phasor pp = (Phasor)summ.get(0); + am.summ.add(pp); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + + am.productt = new ArrayList<Object>(); + if(this.productt.size()!=0){ + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: double dd = ((Double)productt.get(0)).doubleValue(); + am.productt.add(new Double(dd)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + double dd2 = ((Double)productt.get(0)).doubleValue(); + am.productt.add(new Double(dd2)); + } + else{ + long ll = ((Long)productt.get(0)).longValue(); + am.productt.add(new Long(ll)); + } + break; + case 12: BigDecimal bd = (BigDecimal)productt.get(0); + am.productt.add(bd); + break; + case 13: BigInteger bi = (BigInteger)productt.get(0); + am.productt.add(bi); + break; + case 14: Complex cc = (Complex)productt.get(0); + am.productt.add(cc); + break; + case 15: Phasor pp = (Phasor)productt.get(0); + am.productt.add(pp); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + + + switch(this.type){ + case 0: + case 1: double[] dd = this.getArray_as_double().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i])); + break; + case 2: + case 3: float[] ff = this.getArray_as_float().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Float(ff[i])); + break; + case 4: + case 5: long[] ll = this.getArray_as_long().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i])); + break; + case 6: + case 7: int[] ii = this.getArray_as_int().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Integer(ii[i])); + break; + case 8: + case 9: short[] ss = this.getArray_as_short().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Short(ss[i])); + break; + case 10: + case 11: byte[] bb = this.getArray_as_byte().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Byte(bb[i])); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal().clone(); + for(int i=0; i<this.length; i++)am.array.add(bd[i]); + break; + case 13: BigInteger[] bi = this.getArray_as_BigInteger().clone(); + for(int i=0; i<this.length; i++)am.array.add(bi[i]); + break; + case 14: Complex[] ccc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(ccc[i].copy()); + break; + case 15: Phasor[] ppp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(ppp[i].copy()); + break; + case 16: + case 17: char[] cc = this.getArray_as_char().clone(); + for(int i=0; i<this.length; i++)am.array.add(new Character(cc[i])); + break; + case 18: String[] sss = this.getArray_as_String().clone(); + for(int i=0; i<this.length; i++)am.array.add(sss[i]); + break; + } + + return am; + } + + + // POSSIBLE LOSS OF PRECISION MESSAGE + // Suppress possible loss of precisicion messages in an instance of ArrayMaths + public void suppressMessages(){ + this.suppressMessages = true; + } + + // Restore possible loss of precisicion messages in an instance of ArrayMaths + public void restoreMessages(){ + this.suppressMessages = false; + } + + // Suppress possible loss of precisicion messages for all instances in an application + public static void suppressMessagesTotal(){ + Conv.suppressMessagesAM(); + } + + // Restore possible loss of precisicion messages + public static void restoreMessagesTotal(){ + Conv.restoreMessagesAM(); + } + + // INTERNAL ARRAY + // return internal array as double + public double[] array(){ + return this.getArray_as_double(); + } + + public double[] array_as_double(){ + return this.getArray_as_double(); + } + + public double[] getArray_as_double(){ + if(this.suppressMessages)Conv.suppressMessages(); + double[] retArray = new double[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = ((Double)this.array.get(i)).doubleValue(); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Float_to_double((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Long_to_double((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Integer_to_double((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Short_to_double((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Byte_to_double((Byte)this.array.get(i)); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigDecimal_to_double((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigInteger_to_double((BigInteger)this.array.get(i)); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = Double.valueOf(((String)this.array.get(i))); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_int_to_double((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to double is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as Double + public Double[] array_as_Double(){ + return this.getArray_as_Double(); + } + + public Double[] getArray_as_Double(){ + if(this.suppressMessages)Conv.suppressMessages(); + Double[] retArray = new Double[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = (Double)this.array.get(i); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Float_to_Double((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Long_to_Double((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Integer_to_Double((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Short_to_Double((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Byte_to_Double((Byte)this.array.get(i)); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigDecimal_to_Double((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigInteger_to_Double((BigInteger)this.array.get(i)); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = new Double((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_int_to_Double((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to Double is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as Float + public Float[] array_as_Float(){ + return this.getArray_as_Float(); + } + + public Float[] getArray_as_Float(){ + if(this.suppressMessages)Conv.suppressMessages(); + Float[] retArray = new Float[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Double_to_Float((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = (Float)this.array.get(i); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Long_to_Float((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Integer_to_Float((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Short_to_Float((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Byte_to_Float((Byte)this.array.get(i)); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigDecimal_to_Float((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigInteger_to_Float((BigInteger)this.array.get(i)); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = new Float((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_int_to_Float((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to Float is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as float + public float[] array_as_float(){ + return this.getArray_as_float(); + } + + public float[] getArray_as_float(){ + if(this.suppressMessages)Conv.suppressMessages(); + float[] retArray = new float[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Double_to_float((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = ((Float)this.array.get(i)).floatValue(); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Long_to_float((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Integer_to_float((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Short_to_float((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Byte_to_float((Byte)this.array.get(i)); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigDecimal_to_float((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigInteger_to_float((BigInteger)this.array.get(i)); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = (new Float((String)this.array.get(i))).floatValue(); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_int_to_float((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to float is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as long + public long[] array_as_long(){ + return this.getArray_as_long(); + } + + public long[] getArray_as_long(){ + if(this.suppressMessages)Conv.suppressMessages(); + long[] retArray = new long[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Double_to_long((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Float_to_long((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = ((Long)this.array.get(i)).longValue(); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Integer_to_long((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Short_to_long((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Byte_to_long((Byte)this.array.get(i)); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigDecimal_to_long((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigInteger_to_long((BigInteger)this.array.get(i)); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = (new Long((String)this.array.get(i))).longValue(); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_int_to_long((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to long is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as Long + public Long[] array_as_Long(){ + return this.getArray_as_Long(); + } + + public Long[] getArray_as_Long(){ + if(this.suppressMessages)Conv.suppressMessages(); + Long[] retArray = new Long[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Double_to_Long((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Float_to_Long((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = (Long)this.array.get(i); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Integer_to_Long((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Short_to_Long((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Byte_to_Long((Byte)this.array.get(i)); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigDecimal_to_Long((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigInteger_to_Long((BigInteger)this.array.get(i)); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = new Long((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_int_to_Long((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to Long is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + + // return internal array as Integer + public Integer[] array_as_Integer(){ + return this.getArray_as_Integer(); + } + + public Integer[] getArray_as_Integer(){ + if(this.suppressMessages)Conv.suppressMessages(); + Integer[] retArray = new Integer[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Double_to_Integer((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Float_to_Integer((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Long_to_Integer((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = (Integer)this.array.get(i); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Short_to_Integer((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Byte_to_Integer((Byte)this.array.get(i)); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigDecimal_to_Integer((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigInteger_to_Integer((BigInteger)this.array.get(i)); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = new Integer((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = new Integer((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to Integer is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as int + public int[] array_as_int(){ + return this.getArray_as_int(); + } + + public int[] getArray_as_int(){ + if(this.suppressMessages)Conv.suppressMessages(); + int[] retArray = new int[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Double_to_int((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Float_to_int((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Long_to_int((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = ((Integer)this.array.get(i)).intValue(); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Short_to_int((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Byte_to_int((Byte)this.array.get(i)); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigDecimal_to_int((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigInteger_to_int((BigInteger)this.array.get(i)); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = (new Integer((String)this.array.get(i))).intValue(); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = (int)((Character)this.array.get(i)).charValue(); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to int is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as short + public short[] array_as_short(){ + return this.getArray_as_short(); + } + + public short[] getArray_as_short(){ + if(this.suppressMessages)Conv.suppressMessages(); + short[] retArray = new short[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Double_to_short((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Float_to_short((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Long_to_short((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Integer_to_short((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = ((Short)this.array.get(i)).shortValue(); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Byte_to_short((Byte)this.array.get(i)); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigDecimal_to_short((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigInteger_to_short((BigInteger)this.array.get(i)); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = (new Short((String)this.array.get(i))).shortValue(); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_int_to_short((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to short is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + + // return internal array as Short + public Short[] array_as_Short(){ + return this.getArray_as_Short(); + } + + public Short[] getArray_as_Short(){ + if(this.suppressMessages)Conv.suppressMessages(); + Short[] retArray = new Short[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Double_to_Short((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Float_to_Short((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Long_to_Short((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Integer_to_Short((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = (Short)this.array.get(i); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Byte_to_Short((Byte)this.array.get(i)); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigDecimal_to_Short((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigInteger_to_Short((BigInteger)this.array.get(i)); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = new Short((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_int_to_Short((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to Short is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as byte + public byte[] array_as_byte(){ + return this.getArray_as_byte(); + } + + public byte[] getArray_as_byte(){ + if(this.suppressMessages)Conv.suppressMessages(); + byte[] retArray = new byte[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Double_to_byte((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Float_to_byte((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Long_to_byte((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Integer_to_byte((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Short_to_byte((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = ((Byte)this.array.get(i)).byteValue(); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigDecimal_to_byte((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigInteger_to_byte((BigInteger)this.array.get(i)); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = (new Byte((String)this.array.get(i))).byteValue(); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_int_to_byte((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to byte is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as Byte + public Byte[] array_as_Byte(){ + return this.getArray_as_Byte(); + } + + public Byte[] getArray_as_Byte(){ + if(this.suppressMessages)Conv.suppressMessages(); + Byte[] retArray = new Byte[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Double_to_Byte((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Float_to_Byte((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Long_to_Byte((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Integer_to_Byte((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Short_to_Byte((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = (Byte)this.array.get(i); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigDecimal_to_Byte((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigInteger_to_Byte((BigInteger)this.array.get(i)); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = new Byte((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_int_to_Byte((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to Byte is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as BigDecimal + public BigDecimal[] array_as_BigDecimal(){ + return this.getArray_as_BigDecimal(); + } + + public BigDecimal[] getArray_as_BigDecimal(){ + if(this.suppressMessages)Conv.suppressMessages(); + BigDecimal[] retArray = new BigDecimal[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Double_to_BigDecimal((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Float_to_BigDecimal((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Long_to_BigDecimal((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Integer_to_BigDecimal((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Short_to_BigDecimal((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Byte_to_BigDecimal((Byte)this.array.get(i)); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = (BigDecimal)this.array.get(i); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigInteger_to_BigDecimal((BigInteger)this.array.get(i)); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = new BigDecimal((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_int_to_BigDecimal((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to BigDecimal is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as BigInteger + public BigInteger[] array_as_BigInteger(){ + return this.getArray_as_BigInteger(); + } + + public BigInteger[] getArray_as_BigInteger(){ + if(this.suppressMessages)Conv.suppressMessages(); + BigInteger[] retArray = new BigInteger[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Double_to_BigInteger((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Float_to_BigInteger((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Long_to_BigInteger((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Integer_to_BigInteger((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Short_to_BigInteger((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Byte_to_BigInteger((Byte)this.array.get(i)); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_BigDecimal_to_BigInteger((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = (BigInteger)this.array.get(i); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = new BigInteger((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_int_to_BigInteger((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to BigInteger is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as Complex + public Complex[] array_as_Complex(){ + return this.getArray_as_Complex(); + } + + public Complex[] getArray_as_Complex(){ + if(this.suppressMessages)Conv.suppressMessages(); + Complex[] retArray = Complex.oneDarray(this.length); + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = new Complex(((Double)this.array.get(i)).doubleValue()); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = new Complex(((Float)this.array.get(i)).doubleValue()); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = new Complex(Conv.convert_Long_to_double((Long)this.array.get(i))); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = new Complex(Conv.convert_Integer_to_double((Integer)this.array.get(i))); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = new Complex(Conv.convert_Short_to_double((Short)this.array.get(i))); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = new Complex(Conv.convert_Byte_to_double((Byte)this.array.get(i))); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = new Complex(Conv.convert_BigDecimal_to_double((BigDecimal)this.array.get(i))); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = new Complex(Conv.convert_BigInteger_to_double((BigInteger)this.array.get(i))); + break; + case 14: for(int i=0; i<this.length; i++)retArray[i] = (Complex)this.array.get(i); + break; + case 15: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Phasor_to_Complex((Phasor)this.array.get(i)); + break; + case 18: for(int i=0; i<this.length; i++){ + String ss = (String)this.array.get(i); + if(ss.indexOf('i')!=-1 || ss.indexOf('j')!=-1){ + retArray[i] = Complex.valueOf(ss); + } + else{ + retArray[i] = new Complex(Double.valueOf(ss)); + } + } + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = new Complex(Conv.convert_int_to_double((int)((Character)this.array.get(i)).charValue())); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as Phasor + public Phasor[] array_as_Phasor(){ + return this.getArray_as_Phasor(); + } + + public Phasor[] getArray_as_Phasor(){ + if(this.suppressMessages)Conv.suppressMessages(); + Phasor[] retArray = Phasor.oneDarray(this.length); + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = new Phasor(((Double)this.array.get(i)).doubleValue()); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = new Phasor(((Float)this.array.get(i)).doubleValue()); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = new Phasor(Conv.convert_Long_to_double((Long)this.array.get(i))); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = new Phasor(Conv.convert_Integer_to_double((Integer)this.array.get(i))); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = new Phasor(Conv.convert_Short_to_double((Short)this.array.get(i))); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = new Phasor(Conv.convert_Byte_to_double((Byte)this.array.get(i))); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = new Phasor(Conv.convert_BigDecimal_to_double((BigDecimal)this.array.get(i))); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = new Phasor(Conv.convert_BigInteger_to_double((BigInteger)this.array.get(i))); + break; + case 14: for(int i=0; i<this.length; i++)retArray[i] = Conv.convert_Complex_to_Phasor((Complex)this.array.get(i)); + break; + case 15: for(int i=0; i<this.length; i++)retArray[i] = (Phasor)this.array.get(i); + break; + case 18: for(int i=0; i<this.length; i++){ + String ss = ((String)this.array.get(i)).trim(); + if(ss.indexOf('<')!=-1 || ss.indexOf('L')!=-1){ + retArray[i] = Phasor.valueOf(ss); + } + else{ + retArray[i] = new Phasor(Double.valueOf(ss)); + } + } + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = new Phasor(Conv.convert_int_to_double((int)((Character)this.array.get(i)).charValue())); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as Character + public Character[] array_as_Character(){ + return this.getArray_as_Character(); + } + + public Character[] getArray_as_Character(){ + if(this.suppressMessages)Conv.suppressMessages(); + Character[] retArray = new Character[this.length]; + switch(this.type){ + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = new Character((char)(((Integer)this.array.get(i)).intValue())); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = (Character)this.array.get(i); + break; + case 18: boolean test = true; + String[] ss = new String[this.length]; + for(int i=0; i<this.length; i++){ + ss[i] = ((String)this.array.get(i)).trim(); + if(ss[i].length()>1){ + test=false; + break; + } + } + if(test){ + for(int i=0; i<this.length; i++)retArray[i] = new Character(ss[i].charAt(0)); + } + else{ + throw new IllegalArgumentException("The String array elements are too long to be converted to Character"); + } + break; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to char is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + + // return internal array as char + public char[] array_as_char(){ + return this.getArray_as_char(); + } + + public char[] getArray_as_char(){ + if(this.suppressMessages)Conv.suppressMessages(); + char[] retArray = new char[this.length]; + switch(this.type){ + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = (char)(((Integer)this.array.get(i)).intValue()); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = (((Character)this.array.get(i)).charValue()); + break; + case 18: boolean test = true; + String[] ss = new String[this.length]; + for(int i=0; i<this.length; i++){ + ss[i] = ((String)this.array.get(i)).trim(); + if(ss[i].length()>1){ + test=false; + break; + } + } + if(test){ + for(int i=0; i<this.length; i++)retArray[i] = (ss[i].charAt(0)); + } + else{ + throw new IllegalArgumentException("The String array elements are too long to be converted to char"); + } + break; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to char is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as String + public String[] array_as_String(){ + return this.getArray_as_String(); + } + + public String[] getArray_as_String(){ + if(this.suppressMessages)Conv.suppressMessages(); + String[] retArray = new String[this.length]; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)retArray[i] = ((Double)this.array.get(i)).toString(); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)retArray[i] = ((Float)this.array.get(i)).toString(); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)retArray[i] = ((Long)this.array.get(i)).toString(); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)retArray[i] = ((Integer)this.array.get(i)).toString(); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)retArray[i] = ((Short)this.array.get(i)).toString(); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)retArray[i] = ((Byte)this.array.get(i)).toString(); + break; + case 12: for(int i=0; i<this.length; i++)retArray[i] = ((BigDecimal)this.array.get(i)).toString(); + break; + case 13: for(int i=0; i<this.length; i++)retArray[i] = ((BigInteger)this.array.get(i)).toString(); + break; + case 14: for(int i=0; i<this.length; i++)retArray[i] = ((Complex)this.array.get(i)).toString(); + break; + case 15: for(int i=0; i<this.length; i++)retArray[i] = ((Phasor)this.array.get(i)).toString(); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)retArray[i] = ((Character)this.array.get(i)).toString(); + break; + case 18: for(int i=0; i<this.length; i++)retArray[i] = (String)this.array.get(i); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return internal array as Object + public Object[] array_as_Object(){ + return this.getArray_as_Object(); + } + + public Object[] getArray_as_Object(){ + Object[] arrayo= new Object[this.length]; + for(int i=0; i<this.length; i++)arrayo[i] = this.array.get(i); + return arrayo; + } + + // return internal array as Vector + public Vector array_as_Vector(){ + return this.getArray_as_Vector(); + } + + public Vector<Object> getArray_as_Vector(){ + Vector<Object> vec = new Vector<Object>(this.length); + for(int i=0; i<this.length; i++)vec.addElement(array.get(i)); + return vec; + } + + // return internal array as ArrayList + public ArrayList array_as_ArrayList(){ + return this.getArray_as_ArrayList(); + } + + public ArrayList<Object> getArray_as_ArrayList(){ + ArrayList<Object> arrayl = new ArrayList<Object>(this.length); + for(int i=0; i<this.length; i++)arrayl.add(array.get(i)); + return arrayl; + } + + // return internal array as a Row Matrix, Matrix.rowMatrix + public Matrix array_as_Matrix_rowMatrix(){ + return this.getArray_as_Matrix_rowMatrix(); + } + + public Matrix getArray_as_Matrix_rowMatrix(){ + if(this.suppressMessages)Conv.suppressMessages(); + Matrix mat = null; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 18: + case 17: double[] dd = getArray_as_double(); + mat = Matrix.rowMatrix(dd); + break; + case 14: throw new IllegalArgumentException("Complex array cannot be converted to Matrix.rowMatrix - use method getArray_as_Complex_rowMatrix"); + case 15: throw new IllegalArgumentException("Phasor array cannot be converted to Matrix.rowMatrix - use method getArray_as_Phasor_rowMatrix"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return mat; + } + + // return internal array as a Column Matrix, Matrix.columnMatrix + public Matrix array_as_Matrix_columnMatrix(){ + return this.getArray_as_Matrix_columnMatrix(); + } + + public Matrix getArray_as_Matrix_columnMatrix(){ + if(this.suppressMessages)Conv.suppressMessages(); + Matrix mat = null; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 18: + case 17: double[] dd = getArray_as_double(); + mat = Matrix.columnMatrix(dd); + break; + case 14: throw new IllegalArgumentException("Complex array cannot be converted to Matrix.columnMatrix - use method getArray_as_Complex_columnMatrix"); + case 15: throw new IllegalArgumentException("Phasor array cannot be converted to Matrix.columnMatrix - use method getArray_as_Phasor_columnMatrix"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return mat; + } + + // return internal array as a Complex Row Matix, Complex.rowMatrix + public ComplexMatrix array_as_Complex_rowMatrix(){ + return this.getArray_as_Complex_rowMatrix(); + } + + public ComplexMatrix getArray_as_Complex_rowMatrix(){ + Complex[] cc = this.getArray_as_Complex(); + ComplexMatrix mat = ComplexMatrix.rowMatrix(cc); + return mat; + } + + // return internal array as a Complex Column Matrix, Complex.columnMatrix + public ComplexMatrix array_as_Complex_columnMatrix(){ + return this.getArray_as_Complex_columnMatrix(); + } + + public ComplexMatrix getArray_as_Complex_columnMatrix(){ + Complex[] cc = this.getArray_as_Complex(); + ComplexMatrix mat = ComplexMatrix.columnMatrix(cc); + return mat; + } + + // return v as a Phasor Row Matix, Phasor.rowMatrix + public PhasorMatrix array_as_Phasor_rowMatrix(){ + return this.getArray_as_Phasor_rowMatrix(); + } + + public PhasorMatrix getArray_as_Phasor_rowMatrix(){ + Phasor[] cc = this.getArray_as_Phasor(); + PhasorMatrix mat = PhasorMatrix.rowMatrix(cc); + return mat; + } + + // return internal array as a Phasor Column Matrix, Phasor.columnMatrix + public PhasorMatrix array_as_Phasor_columnMatrix(){ + return this.getArray_as_Phasor_columnMatrix(); + } + + public PhasorMatrix getArray_as_Phasor_columnMatrix(){ + Phasor[] cc = this.getArray_as_Phasor(); + PhasorMatrix mat = PhasorMatrix.columnMatrix(cc); + return mat; + } + + // return array of moduli of a Complex internal array + public double[] array_as_modulus_of_Complex(){ + Complex[] cc = this.getArray_as_Complex(); + double[] mod = new double[this.length]; + for(int i=0; i<this.length; i++)mod[i] = cc[i].abs(); + return mod; + } + + // return array of real parts of a Complex internal array + public double[] array_as_real_part_of_Complex(){ + return this.getArray_as_real_part_of_Complex(); + } + + public double[] getArray_as_real_part_of_Complex(){ + Complex[] cc = this.getArray_as_Complex(); + double[] real = new double[this.length]; + for(int i=0; i<this.length; i++)real[i] = cc[i].getReal(); + return real; + } + + // return array of imaginary parts of a Complex internal array + public double[] array_as_imaginary_part_of_Complex(){ + return this.getArray_as_imaginay_part_of_Complex(); + } + + public double[] getArray_as_imaginay_part_of_Complex(){ + Complex[] cc = this.getArray_as_Complex(); + double[] imag = new double[this.length]; + for(int i=0; i<this.length; i++)imag[i] = cc[i].getImag(); + return imag; + } + + // return array of magnitudes of a Phasor internal array + public double[] array_as_magnitude_of_Phasor(){ + return this.getArray_as_magnitude_of_Phasor(); + } + + public double[] getArray_as_magnitude_of_Phasor(){ + Phasor[] pp = this.getArray_as_Phasor(); + double[] magn = new double[this.length]; + for(int i=0; i<this.length; i++)magn[i] = pp[i].getMagnitude(); + return magn; + } + + // return array of phases (in degrees) of a Phasor internal array + public double[] array_as_degrees_phase_of_Phasor(){ + return this.getArray_as_degrees_phase_of_Phasor(); + } + + public double[] getArray_as_degrees_phase_of_Phasor(){ + Phasor[] pp = this.getArray_as_Phasor(); + double[] phased = new double[this.length]; + for(int i=0; i<this.length; i++)phased[i] = pp[i].getPhaseInDegrees(); + return phased; + } + + // return array of phases (in radians) of a Phasor internal array + public double[] array_as_radians_phase_of_Phasor(){ + return this.getArray_as_radians_phase_of_Phasor(); + } + + public double[] getArray_as_radians_phase_of_Phasor(){ + Phasor[] pp = this.getArray_as_Phasor(); + double[] phaser = new double[this.length]; + for(int i=0; i<this.length; i++)phaser[i] = pp[i].getPhaseInRadians(); + return phaser; + } + + + + // GET A SUB-ARRAY + // first index of sub-array = start, last index of sub-array = end + // return sub-array as double + public double[] subarray_as_double(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + double[] retArray = new double[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = ((Double)this.array.get(i)).doubleValue(); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Float_to_double((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Long_to_double((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Integer_to_double((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Short_to_double((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Byte_to_double((Byte)this.array.get(i)); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigDecimal_to_double((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigInteger_to_double((BigInteger)this.array.get(i)); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = Double.valueOf(((String)this.array.get(i))); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_int_to_double((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to double is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as Double + public Double[] subarray_as_Double(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + Double[] retArray = new Double[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = (Double)this.array.get(i); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Float_to_Double((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Long_to_Double((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Integer_to_Double((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Short_to_Double((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Byte_to_Double((Byte)this.array.get(i)); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigDecimal_to_Double((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigInteger_to_Double((BigInteger)this.array.get(i)); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = new Double((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_int_to_Double((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to Double is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as Float + public Float[] subarray_as_Float(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + Float[] retArray = new Float[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Double_to_Float((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = (Float)this.array.get(i); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Long_to_Float((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Integer_to_Float((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Short_to_Float((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Byte_to_Float((Byte)this.array.get(i)); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigDecimal_to_Float((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigInteger_to_Float((BigInteger)this.array.get(i)); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = new Float((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_int_to_Float((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to Float is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as float + public float[] subarray_as_float(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + float[] retArray = new float[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Double_to_float((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = ((Float)this.array.get(i)).floatValue(); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Long_to_float((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Integer_to_float((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Short_to_float((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Byte_to_float((Byte)this.array.get(i)); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigDecimal_to_float((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigInteger_to_float((BigInteger)this.array.get(i)); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = (new Float((String)this.array.get(i))).floatValue(); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_int_to_float((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to float is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as long + public long[] subarray_as_long(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + long[] retArray = new long[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Double_to_long((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Float_to_long((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = ((Long)this.array.get(i)).longValue(); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Integer_to_long((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Short_to_long((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Byte_to_long((Byte)this.array.get(i)); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigDecimal_to_long((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigInteger_to_long((BigInteger)this.array.get(i)); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = (new Long((String)this.array.get(i))).longValue(); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_int_to_long((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to long is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as Long + public Long[] subarray_as_Long(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + Long[] retArray = new Long[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Double_to_Long((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Float_to_Long((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = (Long)this.array.get(i); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Integer_to_Long((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Short_to_Long((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Byte_to_Long((Byte)this.array.get(i)); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigDecimal_to_Long((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigInteger_to_Long((BigInteger)this.array.get(i)); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = new Long((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_int_to_Long((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to Long is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + + // return sub-array as Integer + public Integer[] subarray_as_Integer(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + Integer[] retArray = new Integer[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Double_to_Integer((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Float_to_Integer((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Long_to_Integer((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = (Integer)this.array.get(i); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Short_to_Integer((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Byte_to_Integer((Byte)this.array.get(i)); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigDecimal_to_Integer((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigInteger_to_Integer((BigInteger)this.array.get(i)); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = new Integer((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = new Integer((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to Integer is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as int + public int[] subarray_as_int(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + int[] retArray = new int[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Double_to_int((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Float_to_int((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Long_to_int((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = ((Integer)this.array.get(i)).intValue(); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Short_to_int((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Byte_to_int((Byte)this.array.get(i)); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigDecimal_to_int((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigInteger_to_int((BigInteger)this.array.get(i)); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = (new Integer((String)this.array.get(i))).intValue(); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = (int)((Character)this.array.get(i)).charValue(); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to int is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as short + public short[] subarray_as_short(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + short[] retArray = new short[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Double_to_short((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Float_to_short((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Long_to_short((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Integer_to_short((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = ((Short)this.array.get(i)).shortValue(); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Byte_to_short((Byte)this.array.get(i)); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigDecimal_to_short((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigInteger_to_short((BigInteger)this.array.get(i)); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = (new Short((String)this.array.get(i))).shortValue(); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_int_to_short((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to short is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + + // return sub-array as Short + public Short[] subarray_as_Short(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + Short[] retArray = new Short[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Double_to_Short((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Float_to_Short((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Long_to_Short((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Integer_to_Short((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = (Short)this.array.get(i); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Byte_to_Short((Byte)this.array.get(i)); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigDecimal_to_Short((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigInteger_to_Short((BigInteger)this.array.get(i)); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = new Short((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_int_to_Short((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to Short is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as byte + public byte[] subarray_as_byte(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + byte[] retArray = new byte[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Double_to_byte((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Float_to_byte((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Long_to_byte((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Integer_to_byte((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Short_to_byte((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = ((Byte)this.array.get(i)).byteValue(); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigDecimal_to_byte((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigInteger_to_byte((BigInteger)this.array.get(i)); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = (new Byte((String)this.array.get(i))).byteValue(); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_int_to_byte((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to byte is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as Byte + public Byte[] subarray_as_Byte(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + Byte[] retArray = new Byte[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Double_to_Byte((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Float_to_Byte((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Long_to_Byte((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Integer_to_Byte((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Short_to_Byte((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = (Byte)this.array.get(i); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigDecimal_to_Byte((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigInteger_to_Byte((BigInteger)this.array.get(i)); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = new Byte((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_int_to_Byte((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to Byte is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as BigDecimal + public BigDecimal[] subarray_as_BigDecimal(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + BigDecimal[] retArray = new BigDecimal[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Double_to_BigDecimal((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Float_to_BigDecimal((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Long_to_BigDecimal((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Integer_to_BigDecimal((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Short_to_BigDecimal((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Byte_to_BigDecimal((Byte)this.array.get(i)); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = (BigDecimal)this.array.get(i); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigInteger_to_BigDecimal((BigInteger)this.array.get(i)); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = new BigDecimal((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_int_to_BigDecimal((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to BigDecimal is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as BigInteger + public BigInteger[] subarray_as_BigInteger(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + BigInteger[] retArray = new BigInteger[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Double_to_BigInteger((Double)this.array.get(i)); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Float_to_BigInteger((Float)this.array.get(i)); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Long_to_BigInteger((Long)this.array.get(i)); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Integer_to_BigInteger((Integer)this.array.get(i)); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Short_to_BigInteger((Short)this.array.get(i)); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Byte_to_BigInteger((Byte)this.array.get(i)); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_BigDecimal_to_BigInteger((BigDecimal)this.array.get(i)); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = (BigInteger)this.array.get(i); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = new BigInteger((String)this.array.get(i)); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_int_to_BigInteger((int)((Character)this.array.get(i)).charValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to BigInteger is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as Complex + public Complex[] subarray_as_Complex(int start, int end){ + + if(this.suppressMessages)Conv.suppressMessages(); + Complex[] retArray = Complex.oneDarray(this.length); + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = new Complex(((Double)this.array.get(i)).doubleValue()); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = new Complex(((Float)this.array.get(i)).doubleValue()); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = new Complex(Conv.convert_Long_to_double((Long)this.array.get(i))); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = new Complex(Conv.convert_Integer_to_double((Integer)this.array.get(i))); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = new Complex(Conv.convert_Short_to_double((Short)this.array.get(i))); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = new Complex(Conv.convert_Byte_to_double((Byte)this.array.get(i))); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = new Complex(Conv.convert_BigDecimal_to_double((BigDecimal)this.array.get(i))); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = new Complex(Conv.convert_BigInteger_to_double((BigInteger)this.array.get(i))); + break; + case 14: for(int i=start; i<=end; i++)retArray[i-start] = (Complex)this.array.get(i); + break; + case 15: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Phasor_to_Complex((Phasor)this.array.get(i)); + break; + case 18: for(int i=start; i<=end; i++){ + String ss = (String)this.array.get(i); + if(ss.indexOf('i')!=-1 || ss.indexOf('j')!=-1){ + retArray[i-start] = Complex.valueOf(ss); + } + else{ + retArray[i-start] = new Complex(Double.valueOf(ss)); + } + } + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = new Complex(Conv.convert_int_to_double((int)((Character)this.array.get(i)).charValue())); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as Phasor + public Phasor[] subarray_as_Phasor(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + Phasor[] retArray = Phasor.oneDarray(this.length); + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = new Phasor(((Double)this.array.get(i)).doubleValue()); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = new Phasor(((Float)this.array.get(i)).doubleValue()); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = new Phasor(Conv.convert_Long_to_double((Long)this.array.get(i))); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = new Phasor(Conv.convert_Integer_to_double((Integer)this.array.get(i))); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = new Phasor(Conv.convert_Short_to_double((Short)this.array.get(i))); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = new Phasor(Conv.convert_Byte_to_double((Byte)this.array.get(i))); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = new Phasor(Conv.convert_BigDecimal_to_double((BigDecimal)this.array.get(i))); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = new Phasor(Conv.convert_BigInteger_to_double((BigInteger)this.array.get(i))); + break; + case 14: for(int i=start; i<=end; i++)retArray[i-start] = Conv.convert_Complex_to_Phasor((Complex)this.array.get(i)); + break; + case 15: for(int i=start; i<=end; i++)retArray[i-start] = (Phasor)this.array.get(i); + break; + case 18: for(int i=start; i<=end; i++){ + String ss = ((String)this.array.get(i)).trim(); + if(ss.indexOf('<')!=-1 || ss.indexOf('L')!=-1){ + retArray[i-start] = Phasor.valueOf(ss); + } + else{ + retArray[i-start] = new Phasor(Double.valueOf(ss)); + } + } + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = new Phasor(Conv.convert_int_to_double((int)((Character)this.array.get(i)).charValue())); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as Character + public Character[] subarray_as_Character(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + Character[] retArray = new Character[end-start+1]; + switch(this.type){ + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = new Character((char)(((Integer)this.array.get(i)).intValue())); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = (Character)this.array.get(i); + break; + case 18: boolean test = true; + String[] ss = new String[end-start+1]; + for(int i=start; i<=end; i++){ + ss[i-start] = ((String)this.array.get(i)).trim(); + if(ss[i-start].length()>1){ + test=false; + break; + } + } + if(test){ + for(int i=start; i<=end; i++)retArray[i-start] = new Character(ss[i-start].charAt(0)); + } + else{ + throw new IllegalArgumentException("The String array elements are too long to be converted to Character"); + } + break; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to char is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + + // return sub-array as char + public char[] subarray_as_char(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + char[] retArray = new char[end-start+1]; + switch(this.type){ + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = (char)(((Integer)this.array.get(i)).intValue()); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = (((Character)this.array.get(i)).charValue()); + break; + case 18: boolean test = true; + String[] ss = new String[end-start+1]; + for(int i=start; i<=end; i++){ + ss[i-start] = ((String)this.array.get(i)).trim(); + if(ss[i-start].length()>1){ + test=false; + break; + } + } + if(test){ + for(int i=start; i<=end; i++)retArray[i-start] = (ss[i-start].charAt(0)); + } + else{ + throw new IllegalArgumentException("The String array elements are too long to be converted to char"); + } + break; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a conversion to char is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as String + public String[] subarray_as_String(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + String[] retArray = new String[end-start+1]; + switch(this.type){ + case 0: + case 1: for(int i=start; i<=end; i++)retArray[i-start] = ((Double)this.array.get(i)).toString(); + break; + case 2: + case 3: for(int i=start; i<=end; i++)retArray[i-start] = ((Float)this.array.get(i)).toString(); + break; + case 4: + case 5: for(int i=start; i<=end; i++)retArray[i-start] = ((Long)this.array.get(i)).toString(); + break; + case 6: + case 7: for(int i=start; i<=end; i++)retArray[i-start] = ((Integer)this.array.get(i)).toString(); + break; + case 8: + case 9: for(int i=start; i<=end; i++)retArray[i-start] = ((Short)this.array.get(i)).toString(); + break; + case 10: + case 11: for(int i=start; i<=end; i++)retArray[i-start] = ((Byte)this.array.get(i)).toString(); + break; + case 12: for(int i=start; i<=end; i++)retArray[i-start] = ((BigDecimal)this.array.get(i)).toString(); + break; + case 13: for(int i=start; i<=end; i++)retArray[i-start] = ((BigInteger)this.array.get(i)).toString(); + break; + case 14: for(int i=start; i<=end; i++)retArray[i-start] = ((Complex)this.array.get(i)).toString(); + break; + case 15: for(int i=start; i<=end; i++)retArray[i-start] = ((Phasor)this.array.get(i)).toString(); + break; + case 16: + case 17: for(int i=start; i<=end; i++)retArray[i-start] = ((Character)this.array.get(i)).toString(); + break; + case 18: for(int i=start; i<=end; i++)retArray[i-start] = (String)this.array.get(i); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return retArray; + } + + // return sub-array as Object + public Object[] subarray_as_Object(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + Object[] arrayo= new Object[end-start+1]; + for(int i=start; i<=end; i++)arrayo[i-start] = this.array.get(i); + return arrayo; + } + + // return sub-array as Vector + public Vector<Object> subarray_as_Vector(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + Vector<Object> vec = new Vector<Object>(end-start+1); + for(int i=start; i<=end; i++)vec.addElement(array.get(i)); + return vec; + } + + // return sub-array as ArrayList + public ArrayList<Object> subarray_as_ArrayList(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + ArrayList<Object> arrayl = new ArrayList<Object>(end-start+1); + for(int i=start; i<=end; i++)arrayl.add(array.get(i)); + return arrayl; + } + + // return sub-array as a Row Matrix, Matrix.rowMatrix + public Matrix subarray_as_Matrix_rowMatrix(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + Matrix mat = null; + double[] retArray = new double[end-start+1]; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 18: + case 17: double[] dd = getArray_as_double(); + for(int i=start; i<=end; i++)retArray[i-start] = dd[i]; + mat = Matrix.rowMatrix(retArray); + break; + case 14: throw new IllegalArgumentException("Complex array cannot be converted to Matrix.rowMatrix - use method subarray_as_Complex_rowMatrix"); + case 15: throw new IllegalArgumentException("Phasor array cannot be converted to Matrix.rowMatrix - use method subarray_as_Phasor_rowMatrix"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return mat; + } + + // return sub-array as a Column Matrix, Matrix.columnMatrix + public Matrix subarray_as_Matrix_columnMatrix(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + if(this.suppressMessages)Conv.suppressMessages(); + Matrix mat = null; + double[] retArray = new double[end-start+1]; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 18: + case 17: double[] dd = getArray_as_double(); + for(int i=start; i<=end; i++)retArray[i-start] = dd[i]; + mat = Matrix.columnMatrix(retArray); + break; + case 14: throw new IllegalArgumentException("Complex array cannot be converted to Matrix.columnMatrix - use method subarray_as_Complex_columnMatrix"); + case 15: throw new IllegalArgumentException("Phasor array cannot be converted to Matrix.columnMatrix - use method subarray_as_Phasor_columnMatrix"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return mat; + } + + // return sub-array as a Complex Row Matix, Complex.rowMatrix + public ComplexMatrix subarray_as_Complex_rowMatrix(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + Complex[] cc = this.getArray_as_Complex(); + Complex[] retArray = new Complex[end-start+1]; + for(int i=start; i<=end; i++)retArray[i-start] = cc[i]; + ComplexMatrix mat = ComplexMatrix.rowMatrix(retArray); + return mat; + } + + // return sub-array as a Complex Column Matrix, Complex.columnMatrix + public ComplexMatrix subarray_as_Complex_columnMatrix(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + Complex[] cc = this.getArray_as_Complex(); + Complex[] retArray = new Complex[end-start+1]; + for(int i=start; i<=end; i++)retArray[i-start] = cc[i]; + ComplexMatrix mat = ComplexMatrix.columnMatrix(retArray); + return mat; + } + + // return sub-array as a Phasor Row Matix, Phasor.rowMatrix + public PhasorMatrix subarray_as_Phasor_rowMatrix(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + Phasor[] pp = this.getArray_as_Phasor(); + Phasor[] retArray = new Phasor[end-start+1]; + for(int i=start; i<=end; i++)retArray[i-start] = pp[i]; + PhasorMatrix mat = PhasorMatrix.rowMatrix(retArray); + return mat; + } + + // return sub-array as a Phasor Column Matrix, Phasor.columnMatrix + public PhasorMatrix subarray_as_Phasor_columnMatrix(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + Phasor[] pp = this.getArray_as_Phasor(); + Phasor[] retArray = new Phasor[end-start+1]; + for(int i=start; i<=end; i++)retArray[i-start] = pp[i]; + PhasorMatrix mat = PhasorMatrix.columnMatrix(retArray); + return mat; + } + + // return array of the moduli of a Complex sub-array + public double[] subarray_as_modulus_of_Complex(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + Complex[] cc = this.getArray_as_Complex(); + double[] real = new double[end-start+1]; + for(int i=start; i<=end; i++)real[i-start] = cc[i].abs(); + return real; + } + + // return array of real parts of a Complex sub-array + public double[] subarray_as_real_part_of_Complex(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + Complex[] cc = this.getArray_as_Complex(); + double[] real = new double[end-start+1]; + for(int i=start; i<=end; i++)real[i-start] = cc[i].getReal(); + return real; + } + + // return array of imaginary parts of a Complex sub-array + public double[] subarray_as_imaginay_part_of_Complex(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + Complex[] cc = this.getArray_as_Complex(); + double[] imag = new double[end-start+1]; + for(int i=start; i<=end; i++)imag[i-start] = cc[i].getImag(); + return imag; + } + + // return array of magnitudes of a Phasor sub-array + public double[] subarray_as_magnitude_of_Phasor(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + Phasor[] pp = this.getArray_as_Phasor(); + double[] magn = new double[end-start+1]; + for(int i=start; i<=end; i++)magn[i-start] = pp[i].getMagnitude(); + return magn; + } + + // return array of phases (in degrees) of a Phasor sub-array + public double[] subarray_as_degrees_phase_of_Phasor(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + Phasor[] pp = this.getArray_as_Phasor(); + double[] phased = new double[end-start+1]; + for(int i=start; i<=end; i++)phased[i-start] = pp[i].getPhaseInDegrees(); + return phased; + } + + // return array of phases (in radians) of a Phasor sub-array + public double[] subarray_as_radians_phase_of_Phasor(int start, int end){ + if(end>=this.length)throw new IllegalArgumentException("end, " + end + ", is greater than the highest index, " + (this.length-1)); + Phasor[] pp = this.getArray_as_Phasor(); + double[] phaser = new double[end-start+1]; + for(int i=start; i<=end; i++)phaser[i-start] = pp[i].getPhaseInRadians(); + return phaser; + } + + + + // MAXIMUM AND MINIMUM + // protected method to call search method for maximum and minimum values + // called by public methods + protected void minmax(){ + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(this.getArray_as_Object(), this.minmax, maxminIndices, this.typeName, this.type); + this.maxIndex = maxminIndices[0]; + this.minIndex = maxminIndices[1]; + } + + // protected method that finds the maximum and minimum values + // called by protected method minmax which is called by public methods + protected static void findMinMax(Object[] arrayo, ArrayList<Object> minmaxx, int[] maxminIndices, String[] aTypeName, int aType){ + int maxIndexx = 0; + int minIndexx = 0; + int arraylength = arrayo.length; + switch(aType){ + case 0: + case 1: double[] arrayD = new double[arraylength]; + for(int i=0; i<arraylength; i++)arrayD[i] = ((Double)arrayo[i]).doubleValue(); + double amaxD=arrayD[0]; + double aminD=arrayD[0]; + maxIndexx = 0; + minIndexx = 0; + for(int i=1; i<arraylength; i++){ + if(arrayD[i]>amaxD){ + amaxD = arrayD[i]; + maxIndexx = i; + } + if(arrayD[i]<aminD){ + aminD = arrayD[i]; + minIndexx = i; + } + } + minmaxx.add(new Double(amaxD)); + minmaxx.add(new Double(aminD)); + break; + case 4: + case 5: long[] arrayL = new long[arraylength]; + for(int i=0; i<arraylength; i++)arrayL[i] = ((Long)arrayo[i]).longValue(); + long amaxL=arrayL[0]; + long aminL=arrayL[0]; + maxIndexx = 0; + minIndexx = 0; + for(int i=1; i<arraylength; i++){ + if(arrayL[i]>amaxL){ + amaxL = arrayL[i]; + maxIndexx = i; + } + if(arrayL[i]<aminL){ + aminL = arrayL[i]; + minIndexx = i; + } + } + minmaxx.add(new Long(amaxL)); + minmaxx.add(new Long(aminL)); + break; + case 2: + case 3: float[] arrayF = new float[arraylength]; + for(int i=0; i<arraylength; i++)arrayF[i] = ((Float)arrayo[i]).floatValue(); + float amaxF=arrayF[0]; + float aminF=arrayF[0]; + maxIndexx = 0; + minIndexx = 0; + for(int i=1; i<arraylength; i++){ + if(arrayF[i]>amaxF){ + amaxF = arrayF[i]; + maxIndexx = i; + } + if(arrayF[i]<aminF){ + aminF = arrayF[i]; + minIndexx = i; + } + } + minmaxx.add(new Float(amaxF)); + minmaxx.add(new Float(aminF)); + break; + case 6: + case 7: int[] arrayI = new int[arraylength]; + for(int i=0; i<arraylength; i++)arrayI[i] = ((Integer)arrayo[i]).intValue(); + int amaxI=arrayI[0]; + int aminI=arrayI[0]; + maxIndexx = 0; + minIndexx = 0; + for(int i=1; i<arraylength; i++){ + if(arrayI[i]>amaxI){ + amaxI = arrayI[i]; + maxIndexx = i; + } + if(arrayI[i]<aminI){ + aminI = arrayI[i]; + minIndexx = i; + } + } + minmaxx.add(new Integer(amaxI)); + minmaxx.add(new Integer(aminI)); + break; + case 8: + case 9: short[] arrayS = new short[arraylength]; + for(int i=0; i<arraylength; i++)arrayS[i] = ((Short)arrayo[i]).shortValue(); + short amaxS=arrayS[0]; + short aminS=arrayS[0]; + maxIndexx = 0; + minIndexx = 0; + for(int i=1; i<arraylength; i++){ + if(arrayS[i]>amaxS){ + amaxS = arrayS[i]; + maxIndexx = i; + } + if(arrayS[i]<aminS){ + aminS = arrayS[i]; + minIndexx = i; + } + } + minmaxx.add(new Short(amaxS)); + minmaxx.add(new Short(aminS)); + break; + case 10: + case 11: byte[] arrayB = new byte[arraylength]; + for(int i=0; i<arraylength; i++)arrayB[i] = ((Byte)arrayo[i]).byteValue(); + byte amaxB=arrayB[0]; + byte aminB=arrayB[0]; + maxIndexx = 0; + minIndexx = 0; + for(int i=1; i<arraylength; i++){ + if(arrayB[i]>amaxB){ + amaxB = arrayB[i]; + maxIndexx = i; + } + if(arrayB[i]<aminB){ + aminB = arrayB[i]; + minIndexx = i; + } + } + minmaxx.add(new Byte(amaxB)); + minmaxx.add(new Byte(aminB)); + break; + case 12: BigDecimal[] arrayBD = new BigDecimal[arraylength]; + for(int i=0; i<arraylength; i++)arrayBD[i] = (BigDecimal)arrayo[i]; + BigDecimal amaxBD = arrayBD[0]; + BigDecimal aminBD = arrayBD[0]; + maxIndexx = 0; + minIndexx = 0; + for(int i=1; i<arraylength; i++){ + if(arrayBD[i].compareTo(amaxBD)==1){ + amaxBD = arrayBD[i]; + maxIndexx = i; + } + if(arrayBD[i].compareTo(aminBD)==-1){ + aminBD = arrayBD[i]; + minIndexx = i; + } + } + minmaxx.add(amaxBD); + minmaxx.add(aminBD); + break; + case 13: BigInteger[] arrayBI= new BigInteger[arraylength]; + for(int i=0; i<arraylength; i++)arrayBI[i] = (BigInteger)arrayo[i]; + BigInteger amaxBI = arrayBI[0]; + BigInteger aminBI = arrayBI[0]; + maxIndexx = 0; + minIndexx = 0; + for(int i=1; i<arraylength; i++){ + if(arrayBI[i].compareTo(amaxBI)==1){ + amaxBI = arrayBI[i]; + maxIndexx = i; + } + if(arrayBI[i].compareTo(aminBI)==-1){ + aminBI = arrayBI[i]; + minIndexx = i; + } + } + minmaxx.add(amaxBI); + minmaxx.add(aminBI); + break; + case 16: + case 17: int[] arrayInt = new int[arraylength]; + for(int i=0; i<arraylength; i++)arrayInt[i] = (int)(((Character)arrayo[i]).charValue()); + int amaxInt=arrayInt[0]; + int aminInt=arrayInt[0]; + maxIndexx = 0; + minIndexx = 0; + for(int i=1; i<arraylength; i++){ + if(arrayInt[i]>amaxInt){ + amaxInt = arrayInt[i]; + maxIndexx = i; + } + if(arrayInt[i]<aminInt){ + aminInt = arrayInt[i]; + minIndexx = i; + } + } + minmaxx.add(new Character((char)amaxInt)); + minmaxx.add(new Character((char)aminInt)); + break; + case 14: + case 15: + case 18: System.out.println("ArrayMaths: getMaximum_... or getMinimum_... (findMinMax): the " + aTypeName[aType] + " is not a numerical type for which a maximum or a minimum is meaningful/supported"); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + maxminIndices[0] = maxIndexx; + maxminIndices[1] = minIndexx; + } + + // Return maximum + public double maximum(){ + return this.getMaximum_as_double(); + } + + public double maximum_as_double(){ + return this.getMaximum_as_double(); + } + + public double getMaximum(){ + return this.getMaximum_as_double(); + } + + public double getMaximum_as_double(){ + if(this.suppressMessages)Conv.suppressMessages(); + double max = 0.0D; + switch(this.type){ + case 0: + case 1: max = ((Double)this.minmax.get(0)).doubleValue(); + break; + case 2: + case 3: max = Conv.convert_Float_to_double((Float)this.minmax.get(0)); + break; + case 4: + case 5: max = Conv.convert_Long_to_double((Long)this.minmax.get(0)); + break; + case 6: + case 7: max = Conv.convert_Integer_to_double((Integer)this.minmax.get(0)); + break; + case 8: + case 9: max = Conv.convert_Short_to_double((Short)this.minmax.get(0)); + break; + case 10: + case 11: max = Conv.convert_Byte_to_double((Byte)this.minmax.get(0)); + break; + case 12: max = Conv.convert_BigDecimal_to_double((BigDecimal)this.minmax.get(0)); + break; + case 13: max = Conv.convert_BigInteger_to_double((BigInteger)this.minmax.get(0)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + public Double maximum_as_Double(){ + return this.getMaximum_as_Double(); + } + + public Double getMaximum_as_Double(){ + if(this.suppressMessages)Conv.suppressMessages(); + Double max = new Double(0.0D); + switch(this.type){ + case 0: + case 1: max = (Double)this.minmax.get(0); + break; + case 2: + case 3: max = Conv.convert_Float_to_Double((Float)this.minmax.get(0)); + break; + case 4: + case 5: max = Conv.convert_Long_to_Double((Long)this.minmax.get(0)); + break; + case 6: + case 7: max = Conv.convert_Integer_to_Double((Integer)this.minmax.get(0)); + break; + case 8: + case 9: max = Conv.convert_Short_to_Double((Short)this.minmax.get(0)); + break; + case 10: + case 11: max = Conv.convert_Byte_to_Double((Byte)this.minmax.get(0)); + break; + case 12: max = Conv.convert_BigDecimal_to_Double((BigDecimal)this.minmax.get(0)); + break; + case 13: max = Conv.convert_BigInteger_to_Double((BigInteger)this.minmax.get(0)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + // Return maximum + public Float maximum_as_Float(){ + return this.getMaximum_as_Float(); + } + + public Float getMaximum_as_Float(){ + if(this.suppressMessages)Conv.suppressMessages(); + Float max = new Float(0.0D); + switch(this.type){ + case 0: + case 1: max = Conv.convert_Double_to_Float((Double)this.minmax.get(0)); + break; + case 2: + case 3: max = (Float)this.minmax.get(0); + break; + case 4: + case 5: max = Conv.convert_Long_to_Float((Long)this.minmax.get(0)); + break; + case 6: + case 7: max = Conv.convert_Integer_to_Float((Integer)this.minmax.get(0)); + break; + case 8: + case 9: max = Conv.convert_Short_to_Float((Short)this.minmax.get(0)); + break; + case 10: + case 11: max = Conv.convert_Byte_to_Float((Byte)this.minmax.get(0)); + break; + case 12: max = Conv.convert_BigDecimal_to_Float((BigDecimal)this.minmax.get(0)); + break; + case 13: max = Conv.convert_BigInteger_to_Float((BigInteger)this.minmax.get(0)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + + // Return maximum + public float maximum_as_float(){ + return this.getMaximum_as_float(); + } + + public float getMaximum_as_float(){ + if(this.suppressMessages)Conv.suppressMessages(); + float max = 0.0F; + switch(this.type){ + case 0: + case 1: max = Conv.convert_Double_to_float((Double)this.minmax.get(0)); + break; + case 2: + case 3: max = ((Float)this.minmax.get(0)).floatValue(); + break; + case 4: + case 5: max = Conv.convert_Long_to_float((Long)this.minmax.get(0)); + break; + case 6: + case 7: max = Conv.convert_Integer_to_float((Integer)this.minmax.get(0)); + break; + case 8: + case 9: max = Conv.convert_Short_to_float((Short)this.minmax.get(0)); + break; + case 10: + case 11: max = Conv.convert_Byte_to_float((Byte)this.minmax.get(0)); + break; + case 12: max = Conv.convert_BigDecimal_to_float((BigDecimal)this.minmax.get(0)); + break; + case 13: max = Conv.convert_BigInteger_to_float((BigInteger)this.minmax.get(0)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + // Return maximum + public long maximum_as_long(){ + return this.getMaximum_as_long(); + } + + public long getMaximum_as_long(){ + if(this.suppressMessages)Conv.suppressMessages(); + long max = 0L; + switch(this.type){ + case 0: + case 1: max = Conv.convert_Double_to_long((Double)this.minmax.get(0)); + break; + case 2: + case 3: max = Conv.convert_Float_to_long((Float)this.minmax.get(0)); + break; + case 4: + case 5: max = ((Long)this.minmax.get(0)).longValue(); + break; + case 6: + case 7: max = Conv.convert_Integer_to_long((Integer)this.minmax.get(0)); + break; + case 8: + case 9: max = Conv.convert_Short_to_long((Short)this.minmax.get(0)); + break; + case 10: + case 11: max = Conv.convert_Byte_to_long((Byte)this.minmax.get(0)); + break; + case 12: max = Conv.convert_BigDecimal_to_long((BigDecimal)this.minmax.get(0)); + break; + case 13: max = Conv.convert_BigInteger_to_long((BigInteger)this.minmax.get(0)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + // Return maximum + public Long maximum_as_Long(){ + return this.getMaximum_as_Long(); + } + + public Long getMaximum_as_Long(){ + if(this.suppressMessages)Conv.suppressMessages(); + Long max = new Long(0L); + switch(this.type){ + case 0: + case 1: max = Conv.convert_Double_to_Long((Double)this.minmax.get(0)); + break; + case 2: + case 3: max = Conv.convert_Float_to_Long((Float)this.minmax.get(0)); + break; + case 4: + case 5: max = (Long)this.minmax.get(0); + break; + case 6: + case 7: max = Conv.convert_Integer_to_Long((Integer)this.minmax.get(0)); + break; + case 8: + case 9: max = Conv.convert_Short_to_Long((Short)this.minmax.get(0)); + break; + case 10: + case 11: max = Conv.convert_Byte_to_Long((Byte)this.minmax.get(0)); + break; + case 12: max = Conv.convert_BigDecimal_to_Long((BigDecimal)this.minmax.get(0)); + break; + case 13: max = Conv.convert_BigInteger_to_Long((BigInteger)this.minmax.get(0)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + // Return maximum + public int maximum_as_int(){ + return this.getMaximum_as_int(); + } + + public int getMaximum_as_int(){ + if(this.suppressMessages)Conv.suppressMessages(); + int max = 0; + switch(this.type){ + case 0: + case 1: max = Conv.convert_Double_to_int((Double)this.minmax.get(0)); + break; + case 2: + case 3: max = Conv.convert_Float_to_int((Float)this.minmax.get(0)); + break; + case 4: + case 5: max = Conv.convert_Long_to_int((Long)this.minmax.get(0)); + break; + case 6: + case 7: max = ((Integer)this.minmax.get(0)).intValue(); + break; + case 8: + case 9: max = Conv.convert_Short_to_int((Short)this.minmax.get(0)); + break; + case 10: + case 11: max = Conv.convert_Byte_to_int((Byte)this.minmax.get(0)); + break; + case 12: max = Conv.convert_BigDecimal_to_int((BigDecimal)this.minmax.get(0)); + break; + case 13: max = Conv.convert_BigInteger_to_int((BigInteger)this.minmax.get(0)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + // Return maximum + public Integer maximum_as_Integer(){ + return this.getMaximum_as_Integer(); + } + + public Integer getMaximum_as_Integer(){ + if(this.suppressMessages)Conv.suppressMessages(); + Integer max = new Integer(0); + switch(this.type){ + case 0: + case 1: max = Conv.convert_Double_to_Integer((Double)this.minmax.get(0)); + break; + case 2: + case 3: max = Conv.convert_Float_to_Integer((Float)this.minmax.get(0)); + break; + case 4: + case 5: max = Conv.convert_Long_to_Integer((Long)this.minmax.get(0)); + break; + case 6: + case 7: max = (Integer)this.minmax.get(0); + break; + case 8: + case 9: max = Conv.convert_Short_to_Integer((Short)this.minmax.get(0)); + break; + case 10: + case 11: max = Conv.convert_Byte_to_Integer((Byte)this.minmax.get(0)); + break; + case 12: max = Conv.convert_BigDecimal_to_Integer((BigDecimal)this.minmax.get(0)); + break; + case 13: max = Conv.convert_BigInteger_to_Integer((BigInteger)this.minmax.get(0)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + // Return maximum + public short maximum_as_short(){ + return this.getMaximum_as_short(); + } + + public short getMaximum_as_short(){ + if(this.suppressMessages)Conv.suppressMessages(); + short max = 0; + switch(this.type){ + case 0: + case 1: max = Conv.convert_Double_to_short((Double)this.minmax.get(0)); + break; + case 2: + case 3: max = Conv.convert_Float_to_short((Float)this.minmax.get(0)); + break; + case 4: + case 5: max = Conv.convert_Long_to_short((Long)this.minmax.get(0)); + break; + case 6: + case 7: max = Conv.convert_Integer_to_short((Integer)this.minmax.get(0)); + break; + case 8: + case 9: max = ((Short)this.minmax.get(0)).shortValue(); + break; + case 10: + case 11: max = Conv.convert_Byte_to_short((Byte)this.minmax.get(0)); + break; + case 12: max = Conv.convert_BigDecimal_to_short((BigDecimal)this.minmax.get(0)); + break; + case 13: max = Conv.convert_BigInteger_to_short((BigInteger)this.minmax.get(0)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + // Return maximum + public Short maximum_as_Short(){ + return this.getMaximum_as_Short(); + } + + public Short getMaximum_as_Short(){ + if(this.suppressMessages)Conv.suppressMessages(); + Short max = new Short((short)0); + switch(this.type){ + case 0: + case 1: max = Conv.convert_Double_to_Short((Double)this.minmax.get(0)); + break; + case 2: + case 3: max = Conv.convert_Float_to_Short((Float)this.minmax.get(0)); + break; + case 4: + case 5: max = Conv.convert_Long_to_Short((Long)this.minmax.get(0)); + break; + case 6: + case 7: max = Conv.convert_Integer_to_Short((Integer)this.minmax.get(0)); + break; + case 8: + case 9: max = (Short)this.minmax.get(0); + break; + case 10: + case 11: max = Conv.convert_Byte_to_Short((Byte)this.minmax.get(0)); + break; + case 12: max = Conv.convert_BigDecimal_to_Short((BigDecimal)this.minmax.get(0)); + break; + case 13: max = Conv.convert_BigInteger_to_Short((BigInteger)this.minmax.get(0)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + // Return maximum + public byte maximum_as_byte(){ + return this.getMaximum_as_byte(); + } + + public byte getMaximum_as_byte(){ + if(this.suppressMessages)Conv.suppressMessages(); + byte max = 0; + switch(this.type){ + case 0: + case 1: max = Conv.convert_Double_to_byte((Double)this.minmax.get(0)); + break; + case 2: + case 3: max = Conv.convert_Float_to_byte((Float)this.minmax.get(0)); + break; + case 4: + case 5: max = Conv.convert_Long_to_byte((Long)this.minmax.get(0)); + break; + case 6: + case 7: max = Conv.convert_Integer_to_byte((Integer)this.minmax.get(0)); + break; + case 8: + case 9: max = Conv.convert_Short_to_byte((Short)this.minmax.get(0)); + break; + case 10: + case 11: max = ((Byte)this.minmax.get(0)).byteValue(); + break; + case 12: max = Conv.convert_BigDecimal_to_byte((BigDecimal)this.minmax.get(0)); + break; + case 13: max = Conv.convert_BigInteger_to_byte((BigInteger)this.minmax.get(0)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + // Return maximum + public Byte maximum_as_Byte(){ + return this.getMaximum_as_Byte(); + } + + public Byte getMaximum_as_Byte(){ + if(this.suppressMessages)Conv.suppressMessages(); + Byte max = new Byte((byte)0); + switch(this.type){ + case 0: + case 1: max = Conv.convert_Double_to_Byte((Double)this.minmax.get(0)); + break; + case 2: + case 3: max = Conv.convert_Float_to_Byte((Float)this.minmax.get(0)); + break; + case 4: + case 5: max = Conv.convert_Long_to_Byte((Long)this.minmax.get(0)); + break; + case 6: + case 7: max = Conv.convert_Integer_to_Byte((Integer)this.minmax.get(0)); + break; + case 8: + case 9: max = Conv.convert_Short_to_Byte((Short)this.minmax.get(0)); + break; + case 10: + case 11: max = (Byte)this.minmax.get(0); + break; + case 12: max = Conv.convert_BigDecimal_to_Byte((BigDecimal)this.minmax.get(0)); + break; + case 13: max = Conv.convert_BigInteger_to_Byte((BigInteger)this.minmax.get(0)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + // Return maximum + public BigDecimal maximum_as_BigDecimal(){ + return this.getMaximum_as_BigDecimal(); + } + + public BigDecimal getMaximum_as_BigDecimal(){ + if(this.suppressMessages)Conv.suppressMessages(); + BigDecimal max = new BigDecimal(0.0D); + switch(this.type){ + case 0: + case 1: max = Conv.convert_Double_to_BigDecimal((Double)this.minmax.get(0)); + break; + case 2: + case 3: max = Conv.convert_Float_to_BigDecimal((Float)this.minmax.get(0)); + break; + case 4: + case 5: max = Conv.convert_Long_to_BigDecimal((Long)this.minmax.get(0)); + break; + case 6: + case 7: max = Conv.convert_Integer_to_BigDecimal((Integer)this.minmax.get(0)); + break; + case 8: + case 9: max = Conv.convert_Short_to_BigDecimal((Short)this.minmax.get(0)); + break; + case 10: + case 11: max = Conv.convert_Byte_to_BigDecimal((Byte)this.minmax.get(0)); + break; + case 12: max = (BigDecimal)this.minmax.get(0); + break; + case 13: max = Conv.convert_BigInteger_to_BigDecimal((BigInteger)this.minmax.get(0)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + // Return maximum + public BigInteger maximum_as_BigInteger(){ + return this.getMaximum_as_BigInteger(); + } + + public BigInteger getMaximum_as_BigInteger(){ + if(this.suppressMessages)Conv.suppressMessages(); + BigInteger max = new BigInteger("0"); + switch(this.type){ + case 0: + case 1: max = Conv.convert_Double_to_BigInteger((Double)this.minmax.get(0)); + break; + case 2: + case 3: max = Conv.convert_Float_to_BigInteger((Float)this.minmax.get(0)); + break; + case 4: + case 5: max = Conv.convert_Long_to_BigInteger((Long)this.minmax.get(0)); + break; + case 6: + case 7: max = Conv.convert_Integer_to_BigInteger((Integer)this.minmax.get(0)); + break; + case 8: + case 9: max = Conv.convert_Short_to_BigInteger((Short)this.minmax.get(0)); + break; + case 10: + case 11: max = Conv.convert_Byte_to_BigInteger((Byte)this.minmax.get(0)); + break; + case 12: max = Conv.convert_BigDecimal_to_BigInteger((BigDecimal)this.minmax.get(0)); + break; + case 13: max = (BigInteger)this.minmax.get(0); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + + // Return maximum + public char maximum_as_char(){ + return this.getMaximum_as_char(); + } + + public char getMaximum_as_char(){ + if(this.suppressMessages)Conv.suppressMessages(); + char max = '\u0000'; + switch(this.type){ + case 6: + case 7: max = (char)((Integer)this.minmax.get(1)).intValue(); + break; + case 16: + case 17: max = ((Character)this.minmax.get(1)).charValue(); + break; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a char type maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + // Return maximum + public Character maximum_as_Character(){ + return this.getMaximum_as_Character(); + } + + public Character getMaximum_as_Character(){ + if(this.suppressMessages)Conv.suppressMessages(); + Character max = new Character('\u0000'); + switch(this.type){ + case 6: + case 7: max = new Character((char)((Integer)this.minmax.get(1)).intValue()); + break; + case 16: + case 17: max = (Character)this.minmax.get(1); + break; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a Character type maximum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return max; + } + + // Return minimum + public double minimum(){ + return this.getMinimum_as_double(); + } + + public double minimum_as_double(){ + return this.getMinimum_as_double(); + } + + public double getMinimum(){ + return this.getMinimum_as_double(); + } + + public double getMinimum_as_double(){ + if(this.suppressMessages)Conv.suppressMessages(); + double min = 0.0D; + switch(this.type){ + case 0: + case 1: min = ((Double)this.minmax.get(1)).doubleValue(); + break; + case 2: + case 3: min = Conv.convert_Float_to_double((Float)this.minmax.get(1)); + break; + case 4: + case 5: min = Conv.convert_Long_to_double((Long)this.minmax.get(1)); + break; + case 6: + case 7: min = Conv.convert_Integer_to_double((Integer)this.minmax.get(1)); + break; + case 8: + case 9: min = Conv.convert_Short_to_double((Short)this.minmax.get(1)); + break; + case 10: + case 11: min = Conv.convert_Byte_to_double((Byte)this.minmax.get(1)); + break; + case 12: min = Conv.convert_BigDecimal_to_double((BigDecimal)this.minmax.get(1)); + break; + case 13: min = Conv.convert_BigInteger_to_double((BigInteger)this.minmax.get(1)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public Double minimum_as_Double(){ + return this.getMinimum_as_Double(); + } + + public Double getMinimum_as_Double(){ + if(this.suppressMessages)Conv.suppressMessages(); + Double min = new Double(0.0D); + switch(this.type){ + case 0: + case 1: min = (Double)this.minmax.get(1); + break; + case 2: + case 3: min = Conv.convert_Float_to_Double((Float)this.minmax.get(1)); + break; + case 4: + case 5: min = Conv.convert_Long_to_Double((Long)this.minmax.get(1)); + break; + case 6: + case 7: min = Conv.convert_Integer_to_Double((Integer)this.minmax.get(1)); + break; + case 8: + case 9: min = Conv.convert_Short_to_Double((Short)this.minmax.get(1)); + break; + case 10: + case 11: min = Conv.convert_Byte_to_Double((Byte)this.minmax.get(1)); + break; + case 12: min = Conv.convert_BigDecimal_to_Double((BigDecimal)this.minmax.get(1)); + break; + case 13: min = Conv.convert_BigInteger_to_Double((BigInteger)this.minmax.get(1)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public Float minimum_as_Float(){ + return this.getMinimum_as_Float(); + } + + public Float getMinimum_as_Float(){ + if(this.suppressMessages)Conv.suppressMessages(); + Float min = new Float(0.0D); + switch(this.type){ + case 0: + case 1: min = Conv.convert_Double_to_Float((Double)this.minmax.get(1)); + break; + case 2: + case 3: min = (Float)this.minmax.get(1); + break; + case 4: + case 5: min = Conv.convert_Long_to_Float((Long)this.minmax.get(1)); + break; + case 6: + case 7: min = Conv.convert_Integer_to_Float((Integer)this.minmax.get(1)); + break; + case 8: + case 9: min = Conv.convert_Short_to_Float((Short)this.minmax.get(1)); + break; + case 10: + case 11: min = Conv.convert_Byte_to_Float((Byte)this.minmax.get(1)); + break; + case 12: min = Conv.convert_BigDecimal_to_Float((BigDecimal)this.minmax.get(1)); + break; + case 13: min = Conv.convert_BigInteger_to_Float((BigInteger)this.minmax.get(1)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public float minimum_as_float(){ + return this.getMinimum_as_float(); + } + + public float getMinimum_as_float(){ + if(this.suppressMessages)Conv.suppressMessages(); + float min = 0.0F; + switch(this.type){ + case 0: + case 1: min = Conv.convert_Double_to_float((Double)this.minmax.get(1)); + break; + case 2: + case 3: min = ((Float)this.minmax.get(1)).floatValue(); + break; + case 4: + case 5: min = Conv.convert_Long_to_float((Long)this.minmax.get(1)); + break; + case 6: + case 7: min = Conv.convert_Integer_to_float((Integer)this.minmax.get(1)); + break; + case 8: + case 9: min = Conv.convert_Short_to_float((Short)this.minmax.get(1)); + break; + case 10: + case 11: min = Conv.convert_Byte_to_float((Byte)this.minmax.get(1)); + break; + case 12: min = Conv.convert_BigDecimal_to_float((BigDecimal)this.minmax.get(1)); + break; + case 13: min = Conv.convert_BigInteger_to_float((BigInteger)this.minmax.get(1)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public long minimum_as_long(){ + return this.getMinimum_as_long(); + } + + public long getMinimum_as_long(){ + if(this.suppressMessages)Conv.suppressMessages(); + long min = 0L; + switch(this.type){ + case 0: + case 1: min = Conv.convert_Double_to_long((Double)this.minmax.get(1)); + break; + case 2: + case 3: min = Conv.convert_Float_to_long((Float)this.minmax.get(1)); + break; + case 4: + case 5: min = ((Long)this.minmax.get(1)).longValue(); + break; + case 6: + case 7: min = Conv.convert_Integer_to_long((Integer)this.minmax.get(1)); + break; + case 8: + case 9: min = Conv.convert_Short_to_long((Short)this.minmax.get(1)); + break; + case 10: + case 11: min = Conv.convert_Byte_to_long((Byte)this.minmax.get(1)); + break; + case 12: min = Conv.convert_BigDecimal_to_long((BigDecimal)this.minmax.get(1)); + break; + case 13: min = Conv.convert_BigInteger_to_long((BigInteger)this.minmax.get(1)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public Long minimum_as_Long(){ + return this.getMinimum_as_Long(); + } + + public Long getMinimum_as_Long(){ + if(this.suppressMessages)Conv.suppressMessages(); + Long min = new Long(0L); + switch(this.type){ + case 0: + case 1: min = Conv.convert_Double_to_Long((Double)this.minmax.get(1)); + break; + case 2: + case 3: min = Conv.convert_Float_to_Long((Float)this.minmax.get(1)); + break; + case 4: + case 5: min = (Long)this.minmax.get(1); + break; + case 6: + case 7: min = Conv.convert_Integer_to_Long((Integer)this.minmax.get(1)); + break; + case 8: + case 9: min = Conv.convert_Short_to_Long((Short)this.minmax.get(1)); + break; + case 10: + case 11: min = Conv.convert_Byte_to_Long((Byte)this.minmax.get(1)); + break; + case 12: min = Conv.convert_BigDecimal_to_Long((BigDecimal)this.minmax.get(1)); + break; + case 13: min = Conv.convert_BigInteger_to_Long((BigInteger)this.minmax.get(1)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public int minimum_as_int(){ + return this.getMinimum_as_int(); + } + + public int getMinimum_as_int(){ + if(this.suppressMessages)Conv.suppressMessages(); + int min = 0; + switch(this.type){ + case 0: + case 1: min = Conv.convert_Double_to_int((Double)this.minmax.get(1)); + break; + case 2: + case 3: min = Conv.convert_Float_to_int((Float)this.minmax.get(1)); + break; + case 4: + case 5: min = Conv.convert_Long_to_int((Long)this.minmax.get(1)); + break; + case 6: + case 7: min = ((Integer)this.minmax.get(1)).intValue(); + break; + case 8: + case 9: min = Conv.convert_Short_to_int((Short)this.minmax.get(1)); + break; + case 10: + case 11: min = Conv.convert_Byte_to_int((Byte)this.minmax.get(1)); + break; + case 12: min = Conv.convert_BigDecimal_to_int((BigDecimal)this.minmax.get(1)); + break; + case 13: min = Conv.convert_BigInteger_to_int((BigInteger)this.minmax.get(1)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public Integer minimum_as_Integer(){ + return this.getMinimum_as_Integer(); + } + + public Integer getMinimum_as_Integer(){ + if(this.suppressMessages)Conv.suppressMessages(); + Integer min = new Integer(0); + switch(this.type){ + case 0: + case 1: min = Conv.convert_Double_to_Integer((Double)this.minmax.get(1)); + break; + case 2: + case 3: min = Conv.convert_Float_to_Integer((Float)this.minmax.get(1)); + break; + case 4: + case 5: min = Conv.convert_Long_to_Integer((Long)this.minmax.get(1)); + break; + case 6: + case 7: min = (Integer)this.minmax.get(1); + break; + case 8: + case 9: min = Conv.convert_Short_to_Integer((Short)this.minmax.get(1)); + break; + case 10: + case 11: min = Conv.convert_Byte_to_Integer((Byte)this.minmax.get(1)); + break; + case 12: min = Conv.convert_BigDecimal_to_Integer((BigDecimal)this.minmax.get(1)); + break; + case 13: min = Conv.convert_BigInteger_to_Integer((BigInteger)this.minmax.get(1)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public short minimum_as_short(){ + return this.getMinimum_as_short(); + } + + public short getMinimum_as_short(){ + if(this.suppressMessages)Conv.suppressMessages(); + short min = 0; + switch(this.type){ + case 0: + case 1: min = Conv.convert_Double_to_short((Double)this.minmax.get(1)); + break; + case 2: + case 3: min = Conv.convert_Float_to_short((Float)this.minmax.get(1)); + break; + case 4: + case 5: min = Conv.convert_Long_to_short((Long)this.minmax.get(1)); + break; + case 6: + case 7: min = Conv.convert_Integer_to_short((Integer)this.minmax.get(1)); + break; + case 8: + case 9: min = ((Short)this.minmax.get(1)).shortValue(); + break; + case 10: + case 11: min = Conv.convert_Byte_to_short((Byte)this.minmax.get(1)); + break; + case 12: min = Conv.convert_BigDecimal_to_short((BigDecimal)this.minmax.get(1)); + break; + case 13: min = Conv.convert_BigInteger_to_short((BigInteger)this.minmax.get(1)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public Short minimum_as_Short(){ + return this.getMinimum_as_Short(); + } + + public Short getMinimum_as_Short(){ + if(this.suppressMessages)Conv.suppressMessages(); + Short min = new Short((short)0); + switch(this.type){ + case 0: + case 1: min = Conv.convert_Double_to_Short((Double)this.minmax.get(1)); + break; + case 2: + case 3: min = Conv.convert_Float_to_Short((Float)this.minmax.get(1)); + break; + case 4: + case 5: min = Conv.convert_Long_to_Short((Long)this.minmax.get(1)); + break; + case 6: + case 7: min = Conv.convert_Integer_to_Short((Integer)this.minmax.get(1)); + break; + case 8: + case 9: min = (Short)this.minmax.get(1); + break; + case 10: + case 11: min = Conv.convert_Byte_to_Short((Byte)this.minmax.get(1)); + break; + case 12: min = Conv.convert_BigDecimal_to_Short((BigDecimal)this.minmax.get(1)); + break; + case 13: min = Conv.convert_BigInteger_to_Short((BigInteger)this.minmax.get(1)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public byte minimum_as_byte(){ + return this.getMinimum_as_byte(); + } + + public byte getMinimum_as_byte(){ + if(this.suppressMessages)Conv.suppressMessages(); + byte min = 0; + switch(this.type){ + case 0: + case 1: min = Conv.convert_Double_to_byte((Double)this.minmax.get(1)); + break; + case 2: + case 3: min = Conv.convert_Float_to_byte((Float)this.minmax.get(1)); + break; + case 4: + case 5: min = Conv.convert_Long_to_byte((Long)this.minmax.get(1)); + break; + case 6: + case 7: min = Conv.convert_Integer_to_byte((Integer)this.minmax.get(1)); + break; + case 8: + case 9: min = Conv.convert_Short_to_byte((Short)this.minmax.get(1)); + break; + case 10: + case 11: min = ((Byte)this.minmax.get(1)).byteValue(); + break; + case 12: min = Conv.convert_BigDecimal_to_byte((BigDecimal)this.minmax.get(1)); + break; + case 13: min = Conv.convert_BigInteger_to_byte((BigInteger)this.minmax.get(1)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public Byte minimum_as_Byte(){ + return this.getMinimum_as_Byte(); + } + + public Byte getMinimum_as_Byte(){ + if(this.suppressMessages)Conv.suppressMessages(); + Byte min = new Byte((byte)0); + switch(this.type){ + case 0: + case 1: min = Conv.convert_Double_to_Byte((Double)this.minmax.get(1)); + break; + case 2: + case 3: min = Conv.convert_Float_to_Byte((Float)this.minmax.get(1)); + break; + case 4: + case 5: min = Conv.convert_Long_to_Byte((Long)this.minmax.get(1)); + break; + case 6: + case 7: min = Conv.convert_Integer_to_Byte((Integer)this.minmax.get(1)); + break; + case 8: + case 9: min = Conv.convert_Short_to_Byte((Short)this.minmax.get(1)); + break; + case 10: + case 11: min = (Byte)this.minmax.get(1); + break; + case 12: min = Conv.convert_BigDecimal_to_Byte((BigDecimal)this.minmax.get(1)); + break; + case 13: min = Conv.convert_BigInteger_to_Byte((BigInteger)this.minmax.get(1)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public BigDecimal minimum_as_BigDecimal(){ + return this.getMinimum_as_BigDecimal(); + } + + public BigDecimal getMinimum_as_BigDecimal(){ + if(this.suppressMessages)Conv.suppressMessages(); + BigDecimal min = new BigDecimal(0.0D); + switch(this.type){ + case 0: + case 1: min = Conv.convert_Double_to_BigDecimal((Double)this.minmax.get(1)); + break; + case 2: + case 3: min = Conv.convert_Float_to_BigDecimal((Float)this.minmax.get(1)); + break; + case 4: + case 5: min = Conv.convert_Long_to_BigDecimal((Long)this.minmax.get(1)); + break; + case 6: + case 7: min = Conv.convert_Integer_to_BigDecimal((Integer)this.minmax.get(1)); + break; + case 8: + case 9: min = Conv.convert_Short_to_BigDecimal((Short)this.minmax.get(1)); + break; + case 10: + case 11: min = Conv.convert_Byte_to_BigDecimal((Byte)this.minmax.get(1)); + break; + case 12: min = (BigDecimal)this.minmax.get(1); + break; + case 13: min = Conv.convert_BigInteger_to_BigDecimal((BigInteger)this.minmax.get(1)); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public BigInteger minimum_as_BigInteger(){ + return this.getMinimum_as_BigInteger(); + } + + public BigInteger getMinimum_as_BigInteger(){ + if(this.suppressMessages)Conv.suppressMessages(); + BigInteger min = new BigInteger("0"); + switch(this.type){ + case 0: + case 1: min = Conv.convert_Double_to_BigInteger((Double)this.minmax.get(1)); + break; + case 2: + case 3: min = Conv.convert_Float_to_BigInteger((Float)this.minmax.get(1)); + break; + case 4: + case 5: min = Conv.convert_Long_to_BigInteger((Long)this.minmax.get(1)); + break; + case 6: + case 7: min = Conv.convert_Integer_to_BigInteger((Integer)this.minmax.get(1)); + break; + case 8: + case 9: min = Conv.convert_Short_to_BigInteger((Short)this.minmax.get(1)); + break; + case 10: + case 11: min = Conv.convert_Byte_to_BigInteger((Byte)this.minmax.get(1)); + break; + case 12: min = Conv.convert_BigDecimal_to_BigInteger((BigDecimal)this.minmax.get(1)); + break; + case 13: min = (BigInteger)this.minmax.get(1); + break; + case 14: + case 15: + case 16: + case 17: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public char minimum_as_char(){ + return this.getMinimum_as_char(); + } + + public char getMinimum_as_char(){ + if(this.suppressMessages)Conv.suppressMessages(); + char min = '\u0000'; + switch(this.type){ + case 6: + case 7: min = (char)((Integer)this.minmax.get(1)).intValue(); + break; + case 16: + case 17: min = ((Character)this.minmax.get(1)).charValue(); + break; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a char type minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return minimum + public Character minimum_as_Character(){ + return this.getMinimum_as_Character(); + } + + public Character getMinimum_as_Character(){ + if(this.suppressMessages)Conv.suppressMessages(); + Character min = new Character('\u0000'); + switch(this.type){ + case 6: + case 7: min = new Character((char)((Integer)this.minmax.get(1)).intValue()); + break; + case 16: + case 17: min = (Character)this.minmax.get(1); + break; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 18: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a Character type minimum is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return min; + } + + // Return index of the maximum + public int maximumIndex(){ + return this.maxIndex; + } + + public int getMaximumIndex(){ + return this.maxIndex; + } + + // Return index of the minimum + public int minimumIndex(){ + return this.minIndex; + } + + public int getMinimumIndex(){ + return this.minIndex; + } + + // Returns true if all array elements are, arithmetically, integers, + // returns false if any array element is not, arithmetically, an integer + public boolean isInteger(){ + boolean test = false; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: double[] arrayd = this.getArray_as_double(); + test = Fmath.isInteger(arrayd); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 13: + case 16: + case 17: test = true; + break; + case 12: BigDecimal[] arraybd = this.getArray_as_BigDecimal(); + test = Fmath.isInteger(arraybd); + break; + case 14: + case 15: test = false; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + return test; + } + + + + // ADDITION + // add a constant to the elements of the internal array + public ArrayMaths plus(double constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] + constant)); + am.type = 0; + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.add(new BigDecimal(constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = this.type; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigDecimal hold2 = (new BigDecimal(hold1)).add(new BigDecimal(constant)); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 12; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).plus(constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).plus(new Complex(constant))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ Double.toString(constant)); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a double or float cannot be added to a char"); + case 17: throw new IllegalArgumentException("a double or float cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(Double constant){ + return this.plus(constant.doubleValue()); + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(double[] arrayD){ + if(this.length!=arrayD.length)throw new IllegalArgumentException("The length of the argument array, " + arrayD.length + ", and the length of this instance internal array, " + this.length + ", must be equal"); + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] + arrayD[i])); + am.type = 0; + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.add(new BigDecimal(arrayD[i])); + am.array.add(hold1); + hold1 = null; + } + am.type = this.type; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigDecimal hold2 = (new BigDecimal(hold1)).add(new BigDecimal(arrayD[i])); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 12; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).plus(arrayD[i])); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).plus(new Phasor(arrayD[i]))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ Double.toString(arrayD[i])); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a double or float cannot be added to a char"); + case 17: throw new IllegalArgumentException("a double or float cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + public ArrayMaths plus(Double[] arrayD){ + int nArg = arrayD.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + double[] arrayd = new double[this.length]; + for(int i=0; i<this.length; i++)arrayd[i] = arrayD[i].doubleValue(); + return this.plus(arrayd); + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(float constant){ + double constantd = constant; + return this.plus(constantd); + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(Float constant){ + return this.plus(constant.floatValue()); + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(float[] arrayF){ + if(this.length!=arrayF.length)throw new IllegalArgumentException("The length of the argument array, " + arrayF.length + ", and the length of this instance internal array, " + this.length + ", must be equal"); + double[] arrayD = new double[this.length]; + for(int i=0; i<this.length; i++)arrayD[i] = (double)arrayF[i]; + return this.plus(arrayD); + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(Float[] arrayF){ + int nArg = arrayF.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + double[] arrayd = new double[this.length]; + for(int i=0; i<this.length; i++)arrayd[i] = arrayF[i].doubleValue(); + return this.plus(arrayd); + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(long constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] + (double)constant)); + am.type = 0; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] + constant)); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] + (double)constant)); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.add(new BigDecimal((double)constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.add(new BigInteger((Long.toString(constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).plus((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).plus(new Phasor((double)constant))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ Long.toString(constant)); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a long cannot be added to a char"); + case 17: throw new IllegalArgumentException("a long cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(Long constant){ + long constantl = constant.longValue(); + return this.plus(constantl); + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(long[] arrayL){ + int nArg = arrayL.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] + (double)arrayL[i])); + am.type = 0; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:long max1 = this.getMaximum_as_long(); + ArrayMaths am2 = new ArrayMaths(arrayL); + long max2 = am2.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max1)>=max2){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] + arrayL[i])); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] + (double)arrayL[i])); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.add(new BigDecimal((double)arrayL[i])); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.add(new BigInteger((Long.toString(arrayL[i])))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).plus((double)arrayL[i])); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).plus(new Phasor((double)arrayL[i]))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ Long.toString(arrayL[i])); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a long cannot be added to a char"); + case 17: throw new IllegalArgumentException("a long cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(Long[] arrayL){ + int nArg = arrayL.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + long[] arrayl = new long[this.length]; + for(int i=0; i<this.length; i++)arrayl[i] = arrayL[i].longValue(); + return this.plus(arrayl); + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(int constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] + (double)constant)); + am.type = 0; + break; + case 4:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] + constant)); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] + (double)constant)); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:int maxi = this.getMaximum_as_int(); + int[] lll = this.getArray_as_int(); + if((Integer.MAX_VALUE-maxi)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i] + constant)); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i] + (double)constant)); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.add(new BigDecimal((double)constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.add(new BigInteger((Integer.toString(constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).plus((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).plus(new Phasor((double)constant))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ Integer.toString(constant)); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("an int cannot be added to a char"); + case 17: throw new IllegalArgumentException("an int cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + + return am; + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(Integer constant){ + int constantl = constant.intValue(); + return this.plus(constantl); + } + + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(int[] arrayI){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] + (double)arrayI[i])); + am.type = 0; + break; + case 4: long max = this.getMaximum_as_long(); + ArrayMaths am2 = new ArrayMaths(arrayI); + long max2 = am2.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=max2){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] + arrayI[i])); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] + (double)arrayI[i])); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:int maxi = this.getMaximum_as_int(); + ArrayMaths am22 = new ArrayMaths(arrayI); + int maxi2 = am22.getMaximum_as_int(); + int[] lll = this.getArray_as_int(); + if((Integer.MAX_VALUE-maxi)>=maxi2){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i] + arrayI[i])); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i] + (double)arrayI[i])); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.add(new BigDecimal((double)arrayI[i])); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.add(new BigInteger((Integer.toString(arrayI[i])))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).plus((double)arrayI[i])); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).plus(new Phasor((double)arrayI[i]))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ Integer.toString(arrayI[i])); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("an int cannot be added to a char"); + case 17: throw new IllegalArgumentException("an int cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(Integer[] arrayI){ + int nArg = arrayI.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + int[] arrayl = new int[this.length]; + for(int i=0; i<this.length; i++)arrayl[i] = arrayI[i].intValue(); + return this.plus(arrayl); + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(short constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] + (double)constant)); + am.type = 0; + break; + case 4:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] + (long)constant)); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] + (double)constant)); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:short maxi = this.getMaximum_as_short(); + short[] lll = this.getArray_as_short(); + if((Integer.MAX_VALUE-maxi)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i] + (int)constant)); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i] + (double)constant)); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.add(new BigDecimal((double)constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.add(new BigInteger((Integer.toString((int)constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).plus((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).plus(new Phasor((double)constant))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ Integer.toString(constant)); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a short cannot be added to a char"); + case 17: throw new IllegalArgumentException("a short cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(Short constant){ + short constantl = constant.shortValue(); + return this.plus(constantl); + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(short[] arrayI){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] + (double)arrayI[i])); + am.type = 0; + break; + case 4: long max = this.getMaximum_as_long(); + ArrayMaths am2 = new ArrayMaths(arrayI); + long max2 = am2.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=max2){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] + (long)arrayI[i])); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] + (double)arrayI[i])); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:short maxi = this.getMaximum_as_short(); + ArrayMaths am22 = new ArrayMaths(arrayI); + short maxi2 = am22.getMaximum_as_short(); + short[] lll = this.getArray_as_short(); + if((Integer.MAX_VALUE-maxi)>=maxi2){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i] + (int)arrayI[i])); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i] + (double)arrayI[i])); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.add(new BigDecimal((double)arrayI[i])); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.add(new BigInteger((Integer.toString((int)arrayI[i])))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).plus((double)arrayI[i])); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).plus(new Phasor((double)arrayI[i]))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ Integer.toString(arrayI[i])); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a short cannot be added to a char"); + case 17: throw new IllegalArgumentException("a short cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(Short[] arrayI){ + int nArg = arrayI.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + short[] arrayl = new short[this.length]; + for(int i=0; i<this.length; i++)arrayl[i] = arrayI[i].shortValue(); + return this.plus(arrayl); + } + + + // add a constant to the elements of the internal array + public ArrayMaths plus(BigDecimal constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13:BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].add(constant)); + am.type = 12; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].plus(constant.doubleValue())); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].plus(new Phasor(constant.doubleValue()))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ constant.toString()); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a BigDecimal cannot be added to a char"); + case 17: throw new IllegalArgumentException("a BigDecimal cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(byte constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] + (double)constant)); + am.type = 0; + break; + case 4:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] + (long)constant)); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] + (double)constant)); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:byte maxi = this.getMaximum_as_byte(); + byte[] lll = this.getArray_as_byte(); + if((Integer.MAX_VALUE-maxi)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i] + (int)constant)); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i] + (double)constant)); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.add(new BigDecimal((double)constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.add(new BigInteger((Integer.toString((int)constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).plus((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).plus(new Phasor((double)constant))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ Integer.toString(constant)); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a byte cannot be added to a char"); + case 17: throw new IllegalArgumentException("a byte cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(Byte constant){ + byte constantl = constant.byteValue(); + return this.plus(constantl); + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(byte[] arrayI){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] + (double)arrayI[i])); + am.type = 0; + break; + case 4: long max = this.getMaximum_as_long(); + ArrayMaths am2 = new ArrayMaths(arrayI); + long max2 = am2.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=max2){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] + (long)arrayI[i])); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] + (double)arrayI[i])); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:byte maxi = this.getMaximum_as_byte(); + ArrayMaths am22 = new ArrayMaths(arrayI); + byte maxi2 = am22.getMaximum_as_byte(); + byte[] lll = this.getArray_as_byte(); + if((Integer.MAX_VALUE-maxi)>=maxi2){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i] + (int)arrayI[i])); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i] + (double)arrayI[i])); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.add(new BigDecimal((double)arrayI[i])); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.add(new BigInteger((Integer.toString((int)arrayI[i])))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).plus((double)arrayI[i])); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).plus(new Phasor((double)arrayI[i]))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ Integer.toString(arrayI[i])); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a byte cannot be added to a char"); + case 17: throw new IllegalArgumentException("a byte cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(Byte[] arrayI){ + int nArg = arrayI.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + byte[] arrayl = new byte[this.length]; + for(int i=0; i<this.length; i++)arrayl[i] = arrayI[i].byteValue(); + return this.plus(arrayl); + } + + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(BigDecimal[] arrayBD){ + int nArg = arrayBD.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].add(arrayBD[i])); + Conv.restoreMessages(); + am.type = 12; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].plus(arrayBD[i].doubleValue())); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].plus(new Phasor(arrayBD[i].doubleValue()))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ arrayBD[i].toString()); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a BigDecimal cannot be added to a char"); + case 17: throw new IllegalArgumentException("a BigDecimal cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(BigInteger constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 12: BigDecimal constantBD = Conv.convert_BigInteger_to_BigDecimal(constant); + BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].add(constantBD)); + am.type = 12; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 13:BigInteger[] bi = this.getArray_as_BigInteger(); + for(int i=0; i<this.length; i++)am.array.add(bi[i].add(constant)); + am.type = 13; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].plus(Conv.convert_BigInteger_to_double(constant))); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].plus(new Phasor(Conv.convert_BigInteger_to_double(constant)))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ constant.toString()); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a BigInteger cannot be added to a char"); + case 17: throw new IllegalArgumentException("a BigInteger cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(BigInteger[] arrayBI){ + int nArg = arrayBI.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].add(Conv.convert_BigInteger_to_BigDecimal(arrayBI[i]))); + am.type = 12; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 13: BigInteger[] bi = this.getArray_as_BigInteger(); + for(int i=0; i<this.length; i++)am.array.add(bi[i].add(arrayBI[i])); + am.type = 13; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].plus(Conv.convert_BigInteger_to_double(arrayBI[i]))); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].plus(new Phasor(Conv.convert_BigInteger_to_double(arrayBI[i])))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ arrayBI[i].toString()); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a BigInteger cannot be added to a char"); + case 17: throw new IllegalArgumentException("a BigInteger cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(Complex constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].plus(constant)); + am.type = 14; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].plus(Conv.convert_Complex_to_Phasor(constant))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ constant.toString()); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a Complex cannot be added to a char"); + case 17: throw new IllegalArgumentException("a Complex cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(Complex[] arrayC){ + int nArg = arrayC.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].plus(arrayC[i])); + am.type = 14; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].plus(Conv.convert_Complex_to_Phasor(arrayC[i]))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ arrayC[i].toString()); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a Complex cannot be added to a char"); + case 17: throw new IllegalArgumentException("a Complex cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + + // add a constant to the elements of the internal array + public ArrayMaths plus(Phasor constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].plus(constant)); + am.type = 15; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].plus(Conv.convert_Phasor_to_Complex(constant))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ constant.toString()); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a Phasor cannot be added to a char"); + case 17: throw new IllegalArgumentException("a Phasor cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(Phasor[] arrayP){ + int nArg = arrayP.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].plus(arrayP[i])); + am.type = 15; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].plus(Conv.convert_Phasor_to_Complex(arrayP[i]))); + am.type = this.type; + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(i)+ arrayP[i].toString()); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a Phasor cannot be added to a char"); + case 17: throw new IllegalArgumentException("a Phasor cannot be added to a Character"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(String constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: String[] ss = this.getArray_as_String(); + for(int i=0; i<this.length; i++)am.array.add(ss[i] + constant); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(String[] arraySt){ + int nArg = arraySt.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: String[] ss = this.getArray_as_String(); + for(int i=0; i<this.length; i++)am.array.add(ss[i] + arraySt[i]); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(char constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: String[] ss = this.getArray_as_String(); + for(int i=0; i<this.length; i++)am.array.add(ss[i] + constant); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(char[] arrayCh){ + int nArg = arrayCh.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: String[] ss = this.getArray_as_String(); + for(int i=0; i<this.length; i++)am.array.add(ss[i] + arrayCh[i]); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add a constant to the elements of the internal array + public ArrayMaths plus(Character constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: String[] ss = this.getArray_as_String(); + for(int i=0; i<this.length; i++)am.array.add(ss[i] + constant); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(Character[] arrayCh){ + int nArg = arrayCh.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: String[] ss = this.getArray_as_String(); + for(int i=0; i<this.length; i++)am.array.add(ss[i] + arrayCh[i]); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + return am; + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(Vector<Object> vec){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am1 = new ArrayMaths(); + ArrayMaths am2 = new ArrayMaths(vec); + + switch(am2.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = am2.getArray_as_double(); + am1 = this.plus(dd); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: long[] ll = am2.getArray_as_long(); + am1 = this.plus(ll); + break; + case 12: BigDecimal[] bd = am2.getArray_as_BigDecimal(); + am1 = this.plus(bd); + break; + case 13: BigInteger[] bi = am2.getArray_as_BigInteger(); + am1 = this.plus(bi); + break; + case 14: Complex[] cc = am2.getArray_as_Complex(); + am1 = this.plus(cc); + break; + case 15: Phasor[] pp = am2.getArray_as_Phasor(); + am1 = this.plus(pp); + break; + case 16: + case 17: Character[] ct = am2.getArray_as_Character(); + am1 = this.plus(ct); + break; + case 18: String[] st = am2.getArray_as_String(); + am1 = this.plus(st); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am1.getArray_as_Object(), am1.minmax, maxminIndices, am1.typeName, am1.type); + am1.maxIndex = maxminIndices[0]; + am1.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am1; + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(ArrayList<Object> list){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am1 = new ArrayMaths(); + ArrayMaths am2 = new ArrayMaths(list); + + switch(am2.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = am2.getArray_as_double(); + am1 = this.plus(dd); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: long[] ll = am2.getArray_as_long(); + am1 = this.plus(ll); + break; + case 12: BigDecimal[] bd = am2.getArray_as_BigDecimal(); + am1 = this.plus(bd); + break; + case 13: BigInteger[] bi = am2.getArray_as_BigInteger(); + am1 = this.plus(bi); + break; + case 14: Complex[] cc = am2.getArray_as_Complex(); + am1 = this.plus(cc); + break; + case 15: Phasor[] pp = am2.getArray_as_Phasor(); + am1 = this.plus(pp); + break; + case 16: + case 17: Character[] ct = am2.getArray_as_Character(); + am1 = this.plus(ct); + break; + case 18: String[] st = am2.getArray_as_String(); + am1 = this.plus(st); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am1.getArray_as_Object(), am1.minmax, maxminIndices, am1.typeName, am1.type); + am1.maxIndex = maxminIndices[0]; + am1.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am1; + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(ArrayMaths arrayM){ + ArrayList<Object> arrayl = arrayM.getArray_as_ArrayList(); + return this.plus(arrayl); + } + + // add the elements of an array to the elements of the internal array + public ArrayMaths plus(Stat arrayS){ + ArrayList<Object> arrayl = arrayS.getArray_as_ArrayList(); + return this.plus(arrayl); + } + + // SUBTRACTION + // subtract a constant from the elements of the internal array + public ArrayMaths minus(double constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] - constant)); + am.type = 0; + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.subtract(new BigDecimal(constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = this.type; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigDecimal hold2 = (new BigDecimal(hold1)).subtract(new BigDecimal(constant)); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 12; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).minus(constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).minus(new Complex(constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a double or float cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a double or float cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a double or float cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(Double constant){ + return this.minus(constant.doubleValue()); + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(double[] arrayD){ + if(this.length!=arrayD.length)throw new IllegalArgumentException("The length of the argument array, " + arrayD.length + ", and the length of this instance internal array, " + this.length + ", must be equal"); + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] - arrayD[i])); + am.type = 0; + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.subtract(new BigDecimal(arrayD[i])); + am.array.add(hold1); + hold1 = null; + } + am.type = this.type; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigDecimal hold2 = (new BigDecimal(hold1)).subtract(new BigDecimal(arrayD[i])); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 12; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).minus(arrayD[i])); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).minus(new Phasor(arrayD[i]))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a double or float cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a double or float cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a double or float cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(Double[] arrayD){ + int nArg = arrayD.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + double[] arrayd = new double[this.length]; + for(int i=0; i<this.length; i++)arrayd[i] = arrayD[i].doubleValue(); + return this.minus(arrayd); + } + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(float constant){ + double constantd = constant; + return this.minus(constantd); + } + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(Float constant){ + return this.minus(constant.floatValue()); + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(float[] arrayF){ + if(this.length!=arrayF.length)throw new IllegalArgumentException("The length of the argument array, " + arrayF.length + ", and the length of this instance internal array, " + this.length + ", must be equal"); + double[] arrayD = new double[this.length]; + for(int i=0; i<this.length; i++)arrayD[i] = (double)arrayF[i]; + return this.minus(arrayD); + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(Float[] arrayF){ + int nArg = arrayF.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + double[] arrayd = new double[this.length]; + for(int i=0; i<this.length; i++)arrayd[i] = arrayF[i].doubleValue(); + return this.minus(arrayd); + } + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(long constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] - (double)constant)); + am.type = 0; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] - constant)); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] - (double)constant)); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.subtract(new BigDecimal((double)constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.subtract(new BigInteger((Long.toString(constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).minus((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).minus(new Phasor((double)constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a long cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a long cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a long cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(Long constant){ + long constantl = constant.longValue(); + return this.minus(constantl); + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(long[] arrayL){ + int nArg = arrayL.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] - (double)arrayL[i])); + am.type = 0; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:long max1 = this.getMaximum_as_long(); + ArrayMaths am2 = new ArrayMaths(arrayL); + long max2 = am2.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max1)>=max2){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] - arrayL[i])); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] - (double)arrayL[i])); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.subtract(new BigDecimal((double)arrayL[i])); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.subtract(new BigInteger((Long.toString(arrayL[i])))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).minus((double)arrayL[i])); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).minus(new Phasor((double)arrayL[i]))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a long cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a long cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a long cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(Long[] arrayL){ + int nArg = arrayL.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + long[] arrayl = new long[this.length]; + for(int i=0; i<this.length; i++)arrayl[i] = arrayL[i].longValue(); + return this.minus(arrayl); + } + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(int constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] - (double)constant)); + am.type = 0; + break; + case 4:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] - constant)); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] - (double)constant)); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:int maxi = this.getMaximum_as_int(); + int[] lll = this.getArray_as_int(); + if((Integer.MAX_VALUE-maxi)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i] - constant)); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i] - (double)constant)); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.subtract(new BigDecimal((double)constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.subtract(new BigInteger((Integer.toString(constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).minus((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).minus(new Phasor((double)constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("an int cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("an int cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("an int cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(Integer constant){ + int constantl = constant.intValue(); + return this.minus(constantl); + } + + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(int[] arrayI){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] - (double)arrayI[i])); + am.type = 0; + break; + case 4: long max = this.getMaximum_as_long(); + ArrayMaths am2 = new ArrayMaths(arrayI); + long max2 = am2.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=max2){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] - arrayI[i])); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] - (double)arrayI[i])); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:int maxi = this.getMaximum_as_int(); + ArrayMaths am22 = new ArrayMaths(arrayI); + int maxi2 = am22.getMaximum_as_int(); + int[] lll = this.getArray_as_int(); + if((Integer.MAX_VALUE-maxi)>=maxi2){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i] - arrayI[i])); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i] - (double)arrayI[i])); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.subtract(new BigDecimal((double)arrayI[i])); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.subtract(new BigInteger((Integer.toString(arrayI[i])))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).minus((double)arrayI[i])); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).minus(new Phasor((double)arrayI[i]))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("an int cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("an int cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("an int cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(Integer[] arrayI){ + int nArg = arrayI.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + int[] arrayl = new int[this.length]; + for(int i=0; i<this.length; i++)arrayl[i] = arrayI[i].intValue(); + return this.minus(arrayl); + } + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(short constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] - (double)constant)); + am.type = 0; + break; + case 4:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] - (long)constant)); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] - (double)constant)); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:short maxi = this.getMaximum_as_short(); + short[] lll = this.getArray_as_short(); + if((Integer.MAX_VALUE-maxi)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i] - (int)constant)); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i] - (double)constant)); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.subtract(new BigDecimal((double)constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.subtract(new BigInteger((Integer.toString((int)constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).minus((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).minus(new Phasor((double)constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a short cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a short cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a short cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(Short constant){ + short constantl = constant.shortValue(); + return this.minus(constantl); + } + + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(short[] arrayI){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] - (double)arrayI[i])); + am.type = 0; + break; + case 4: long max = this.getMaximum_as_long(); + ArrayMaths am2 = new ArrayMaths(arrayI); + long max2 = am2.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=max2){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] - (long)arrayI[i])); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] - (double)arrayI[i])); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:short maxi = this.getMaximum_as_short(); + ArrayMaths am22 = new ArrayMaths(arrayI); + short maxi2 = am22.getMaximum_as_short(); + short[] lll = this.getArray_as_short(); + if((Integer.MAX_VALUE-maxi)>=maxi2){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i] - (int)arrayI[i])); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i] - (double)arrayI[i])); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.subtract(new BigDecimal((double)arrayI[i])); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.subtract(new BigInteger((Integer.toString((int)arrayI[i])))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).minus((double)arrayI[i])); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).minus(new Phasor((double)arrayI[i]))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a long cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a long cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a short cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(Short[] arrayI){ + int nArg = arrayI.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + short[] arrayl = new short[this.length]; + for(int i=0; i<this.length; i++)arrayl[i] = arrayI[i].shortValue(); + return this.minus(arrayl); + } + + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(BigDecimal constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13:BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].subtract(constant)); + am.type = 12; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].minus(constant.doubleValue())); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].minus(new Phasor(constant.doubleValue()))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a BigDecimal cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a BigDecimal cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a BigDecimal cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(byte constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] - (double)constant)); + am.type = 0; + break; + case 4:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] - (long)constant)); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] - (double)constant)); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:byte maxi = this.getMaximum_as_byte(); + byte[] lll = this.getArray_as_byte(); + if((Integer.MAX_VALUE-maxi)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i] - (int)constant)); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i] - (double)constant)); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.subtract(new BigDecimal((double)constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.subtract(new BigInteger((Integer.toString((int)constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).minus((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).minus(new Phasor((double)constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a byte cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a byte cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a byte cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(Byte constant){ + byte constantl = constant.byteValue(); + return this.minus(constantl); + } + + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(byte[] arrayI){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i] - (double)arrayI[i])); + am.type = 0; + break; + case 4: long max = this.getMaximum_as_long(); + ArrayMaths am2 = new ArrayMaths(arrayI); + long max2 = am2.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=max2){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i] - (long)arrayI[i])); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i] - (double)arrayI[i])); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:byte maxi = this.getMaximum_as_byte(); + ArrayMaths am22 = new ArrayMaths(arrayI); + byte maxi2 = am22.getMaximum_as_byte(); + byte[] lll = this.getArray_as_byte(); + if((Integer.MAX_VALUE-maxi)>=maxi2){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i] - (int)arrayI[i])); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i] - (double)arrayI[i])); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.subtract(new BigDecimal((double)arrayI[i])); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.subtract(new BigInteger((Integer.toString((int)arrayI[i])))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).minus((double)arrayI[i])); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).minus(new Phasor((double)arrayI[i]))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a byte cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a byte cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a byte cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(Byte[] arrayI){ + int nArg = arrayI.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + byte[] arrayl = new byte[this.length]; + for(int i=0; i<this.length; i++)arrayl[i] = arrayI[i].byteValue(); + return this.minus(arrayl); + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(BigDecimal[] arrayBD){ + int nArg = arrayBD.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].add(arrayBD[i])); + Conv.restoreMessages(); + am.type = 12; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].minus(arrayBD[i].doubleValue())); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].minus(new Phasor(arrayBD[i].doubleValue()))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a BigDecimal cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a BigDecimal cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a BigDecimalcannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(BigInteger constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 12: BigDecimal constantBD = Conv.convert_BigInteger_to_BigDecimal(constant); + BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].add(constantBD)); + am.type = 12; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 13:BigInteger[] bi = this.getArray_as_BigInteger(); + for(int i=0; i<this.length; i++)am.array.add(bi[i].subtract(constant)); + am.type = 13; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].minus(Conv.convert_BigInteger_to_double(constant))); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].minus(new Phasor(Conv.convert_BigInteger_to_double(constant)))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a BigInteger cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a BigInteger cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a BigInteger cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(BigInteger[] arrayBI){ + int nArg = arrayBI.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].add(Conv.convert_BigInteger_to_BigDecimal(arrayBI[i]))); + am.type = 12; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 13: BigInteger[] bi = this.getArray_as_BigInteger(); + for(int i=0; i<this.length; i++)am.array.add(bi[i].add(arrayBI[i])); + am.type = 13; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].minus(Conv.convert_BigInteger_to_double(arrayBI[i]))); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].minus(new Phasor(Conv.convert_BigInteger_to_double(arrayBI[i])))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a BigInteger cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a BigInteger cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a BigInteger cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(Complex constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].minus(constant)); + am.type = 14; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].minus(Conv.convert_Complex_to_Phasor(constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a Complex cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a Complex cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a Complex cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(Complex[] arrayC){ + int nArg = arrayC.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].minus(arrayC[i])); + am.type = 14; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].minus(Conv.convert_Complex_to_Phasor(arrayC[i]))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a Complex cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a Complex cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a Complex cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + // subtract a constant from the elements of the internal array + public ArrayMaths minus(Phasor constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].minus(constant)); + am.type = 15; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].minus(Conv.convert_Phasor_to_Complex(constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a Phasor cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a Phasor cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a Phasor cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(Phasor[] arrayP){ + int nArg = arrayP.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].minus(arrayP[i])); + am.type = 15; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].minus(Conv.convert_Phasor_to_Complex(arrayP[i]))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a Phasor cannot be subtracted from a char"); + case 17: throw new IllegalArgumentException("a Phasor cannot be subtracted from a Character"); + case 18: throw new IllegalArgumentException("a Phasor cannot be subtracted from a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(Vector<Object> vec){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am1 = new ArrayMaths(); + ArrayMaths am2 = new ArrayMaths(vec); + + switch(am2.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = am2.getArray_as_double(); + am1 = this.minus(dd); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: long[] ll = am2.getArray_as_long(); + am1 = this.minus(ll); + break; + case 12: BigDecimal[] bd = am2.getArray_as_BigDecimal(); + am1 = this.minus(bd); + break; + case 13: BigInteger[] bi = am2.getArray_as_BigInteger(); + am1 = this.minus(bi); + break; + case 14: Complex[] cc = am2.getArray_as_Complex(); + am1 = this.minus(cc); + break; + case 15: Phasor[] pp = am2.getArray_as_Phasor(); + am1 = this.minus(pp); + break; + case 16: throw new IllegalArgumentException("ArrayList/char subtraction not allowed"); + case 17: throw new IllegalArgumentException("ArrayList/Character subtraction not allowed"); + case 18: throw new IllegalArgumentException("ArrayList/String subtraction not allowed"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am1.getArray_as_Object(), am1.minmax, maxminIndices, am1.typeName, am1.type); + am1.maxIndex = maxminIndices[0]; + am1.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am1; + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(ArrayList<Object> list){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am1 = new ArrayMaths(); + ArrayMaths am2 = new ArrayMaths(list); + + switch(am2.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = am2.getArray_as_double(); + am1 = this.minus(dd); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: long[] ll = am2.getArray_as_long(); + am1 = this.minus(ll); + break; + case 12: BigDecimal[] bd = am2.getArray_as_BigDecimal(); + am1 = this.minus(bd); + break; + case 13: BigInteger[] bi = am2.getArray_as_BigInteger(); + am1 = this.minus(bi); + break; + case 14: Complex[] cc = am2.getArray_as_Complex(); + am1 = this.minus(cc); + break; + case 15: Phasor[] pp = am2.getArray_as_Phasor(); + am1 = this.minus(pp); + break; + case 16: throw new IllegalArgumentException("ArrayList/char subtraction not allowed"); + case 17: throw new IllegalArgumentException("ArrayList/Character subtraction not allowed"); + case 18: throw new IllegalArgumentException("ArrayList/String subtraction not allowed"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am1.getArray_as_Object(), am1.minmax, maxminIndices, am1.typeName, am1.type); + am1.maxIndex = maxminIndices[0]; + am1.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am1; + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(ArrayMaths arrayM){ + ArrayList<Object> arrayl = arrayM.getArray_as_ArrayList(); + return this.minus(arrayl); + } + + // Subtract the elements of an array from the elements of the internal array + public ArrayMaths minus(Stat arrayS){ + ArrayList<Object> arrayl = arrayS.getArray_as_ArrayList(); + return this.minus(arrayl); + } + + // MULTIPLICATION + // multiply the elements of the internal array by a constant + public ArrayMaths times(double constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i]*constant)); + am.type = 0; + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.multiply(new BigDecimal(constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = this.type; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigDecimal hold2 = (new BigDecimal(hold1)).multiply(new BigDecimal(constant)); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 12; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).times(constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).times(new Complex(constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a double or float cannot be multiplied by a char"); + case 17: throw new IllegalArgumentException("a double or float cannot be multiplied by a Character"); + case 18: throw new IllegalArgumentException("a double or float cannot be multiplied by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // multiply the elements of the internal array by a constant + public ArrayMaths times(Double constant){ + return this.times(constant.doubleValue()); + } + + // multiply the elements of the internal array by a constant + public ArrayMaths times(float constant){ + double constantd = constant; + return this.times(constantd); + } + + // multiply the elements of the internal array by a constant + public ArrayMaths times(Float constant){ + return this.times(constant.floatValue()); + } + + // multiply the elements of the internal array by a constant + public ArrayMaths times(long constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i]*(double)constant)); + am.type = 0; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i]*constant)); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i]*(double)constant)); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.multiply(new BigDecimal((double)constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.multiply(new BigInteger((Long.toString(constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).times((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).times(new Phasor((double)constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a long cannot be multiplied by a char"); + case 17: throw new IllegalArgumentException("a long cannot be multiplied by a Character"); + case 18: throw new IllegalArgumentException("a long cannot be multiplied by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // multiply the elements of the internal array by a constant + public ArrayMaths times(Long constant){ + long constantl = constant.longValue(); + return this.times(constantl); + } + + // multiply the elements of the internal array by a constant + public ArrayMaths times(int constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i]*(double)constant)); + am.type = 0; + break; + case 4:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i]*constant)); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i]*(double)constant)); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:int maxi = this.getMaximum_as_int(); + int[] lll = this.getArray_as_int(); + if((Integer.MAX_VALUE-maxi)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i]*constant)); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i]*(double)constant)); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.multiply(new BigDecimal((double)constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.multiply(new BigInteger((Integer.toString(constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).times((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).times(new Phasor((double)constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("an int cannot be multiplied by a char"); + case 17: throw new IllegalArgumentException("an int cannot be multiplied by a Character"); + case 18: throw new IllegalArgumentException("an int cannot be multiplied by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // multiply the elements of the internal array by a constant + public ArrayMaths times(Integer constant){ + int constantl = constant.intValue(); + return this.times(constantl); + } + + // multiply the elements of the internal array by a constant + public ArrayMaths times(short constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i]*(double)constant)); + am.type = 0; + break; + case 4:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i]*(long)constant)); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i]*(double)constant)); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:short maxi = this.getMaximum_as_short(); + short[] lll = this.getArray_as_short(); + if((Integer.MAX_VALUE-maxi)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i]*(int)constant)); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i]*(double)constant)); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.multiply(new BigDecimal((double)constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.multiply(new BigInteger((Integer.toString((int)constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).times((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).times(new Phasor((double)constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a short cannot be multiplied by a char"); + case 17: throw new IllegalArgumentException("a short cannot be multiplied by a Character"); + case 18: throw new IllegalArgumentException("a short cannot be multiplied by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // multiply the elements of the internal array by a constant + public ArrayMaths times(Short constant){ + short constantl = constant.shortValue(); + return this.times(constantl); + } + + + // multiply the elements of the internal array by a constant + public ArrayMaths times(BigDecimal constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13:BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].multiply(constant)); + am.type = 12; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].times(constant.doubleValue())); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].times(new Phasor(constant.doubleValue()))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a BigDecimal cannot be multiplied by a char"); + case 17: throw new IllegalArgumentException("a BigDecimal cannot be multiplied by a Character"); + case 18: throw new IllegalArgumentException("a BigDecimal cannot be multiplied by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // multiply the elements of the internal array by a constant + public ArrayMaths times(byte constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i]*(double)constant)); + am.type = 0; + break; + case 4:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i]*(long)constant)); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i]*(double)constant)); + am.type = 0; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:byte maxi = this.getMaximum_as_byte(); + byte[] lll = this.getArray_as_byte(); + if((Integer.MAX_VALUE-maxi)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i]*(int)constant)); + am.type = 6; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i]*(double)constant)); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.multiply(new BigDecimal((double)constant)); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.multiply(new BigInteger((Integer.toString((int)constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).times((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).times(new Phasor((double)constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a byte cannot be multiplied by a char"); + case 17: throw new IllegalArgumentException("a byte cannot be multiplied by a Character"); + case 18: throw new IllegalArgumentException("a byte cannot be multiplied by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // multiply the elements of the internal array by a constant + public ArrayMaths times(Byte constant){ + byte constantl = constant.byteValue(); + return this.times(constantl); + } + + + // multiply the elements of the internal array by a constant + public ArrayMaths times(BigInteger constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 12: BigDecimal constantBD = Conv.convert_BigInteger_to_BigDecimal(constant); + BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].add(constantBD)); + am.type = 12; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 13:BigInteger[] bi = this.getArray_as_BigInteger(); + for(int i=0; i<this.length; i++)am.array.add(bi[i].multiply(constant)); + am.type = 13; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].times(Conv.convert_BigInteger_to_double(constant))); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].times(new Phasor(Conv.convert_BigInteger_to_double(constant)))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a BigInteger cannot be multiplied by a char"); + case 17: throw new IllegalArgumentException("a BigInteger cannot be multiplied by a Character"); + case 18: throw new IllegalArgumentException("a BigInteger cannot be multiplied by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + + // multiply the elements of the internal array by a constant + public ArrayMaths times(Complex constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].times(constant)); + am.type = 14; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].times(Conv.convert_Complex_to_Phasor(constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a Complex cannot be multiplied by a char"); + case 17: throw new IllegalArgumentException("a Complex cannot be multiplied by a Character"); + case 18: throw new IllegalArgumentException("a Complex cannot be multiplied by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + + // multiply the elements of the internal array by a constant + public ArrayMaths times(Phasor constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].times(constant)); + am.type = 15; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].times(Conv.convert_Phasor_to_Complex(constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a Phasor cannot be multiplied by a char"); + case 17: throw new IllegalArgumentException("a Phasor cannot be multiplied by a Character"); + case 18: throw new IllegalArgumentException("a Phasor cannot be multiplied by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + + + // DIVISION + // divide the elements of the internal array by a constant + public ArrayMaths over(double constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i]/constant)); + am.type = 0; + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.divide(new BigDecimal(constant), BigDecimal.ROUND_HALF_UP); + am.array.add(hold1); + hold1 = null; + } + am.type = this.type; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigDecimal hold2 = (new BigDecimal(hold1)).divide(new BigDecimal(constant), BigDecimal.ROUND_HALF_UP); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 12; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).over(constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).over(new Complex(constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a double or float cannot be divided by a char"); + case 17: throw new IllegalArgumentException("a double or float cannot be divided by a Character"); + case 18: throw new IllegalArgumentException("a double or float cannot be divided by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // divide the elements of the internal array by a constant + public ArrayMaths over(Double constant){ + return this.over(constant.doubleValue()); + } + + // divide the elements of the internal array by a constant + public ArrayMaths over(float constant){ + double constantd = constant; + return this.over(constantd); + } + + // divide the elements of the internal array by a constant + public ArrayMaths over(Float constant){ + return this.over(constant.floatValue()); + } + + // divide the elements of the internal array by a constant + public ArrayMaths over(long constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i]/(double)constant)); + am.type = 0; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + if((Long.MAX_VALUE-max)>=constant){ + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i]/constant)); + am.type = 4; + } + else{ + for(int i=0; i<this.length; i++)am.array.add(new Double((double)ll[i]/(double)constant)); + am.type = 0; + } + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.divide(new BigDecimal((double)constant), BigDecimal.ROUND_HALF_UP); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.divide(new BigInteger((Long.toString(constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).over((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).over(new Phasor((double)constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a long cannot be divided by a char"); + case 17: throw new IllegalArgumentException("a long cannot be divided by a Character"); + case 18: throw new IllegalArgumentException("a long cannot be divided by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // divide the elements of the internal array by a constant + public ArrayMaths over(Long constant){ + long constantl = constant.longValue(); + return this.over(constantl); + } + + + // divide the elements of the internal array by a constant + public ArrayMaths over(int constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i]/(double)constant)); + am.type = 0; + break; + case 4:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i]/constant)); + am.type = 4; + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:int maxi = this.getMaximum_as_int(); + int[] lll = this.getArray_as_int(); + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i]/constant)); + am.type = 6; + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.divide(new BigDecimal((double)constant), BigDecimal.ROUND_HALF_UP); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.divide(new BigInteger((Integer.toString(constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).over((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).over(new Phasor((double)constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("an int cannot be divided by a char"); + case 17: throw new IllegalArgumentException("an int cannot be divided by a Character"); + case 18: throw new IllegalArgumentException("an int cannot be divided by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // divide the elements of the internal array by a constant + public ArrayMaths over(Integer constant){ + int constantl = constant.intValue(); + return this.over(constantl); + } + + // divide the elements of the internal array by a constant + public ArrayMaths over(short constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i]/(double)constant)); + am.type = 0; + break; + case 4:long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i]/(long)constant)); + am.type = 4; + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:short maxi = this.getMaximum_as_short(); + short[] lll = this.getArray_as_short(); + for(int i=0; i<this.length; i++)am.array.add(new Integer(lll[i]/(int)constant)); + am.type = 6; + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.divide(new BigDecimal((double)constant), BigDecimal.ROUND_HALF_UP); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.divide(new BigInteger((Integer.toString((int)constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).over((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).over(new Phasor((double)constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a short cannot be divided by a char"); + case 17: throw new IllegalArgumentException("a short cannot be divided by a Character"); + case 18: throw new IllegalArgumentException("a short cannot be divided by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // divide the elements of the internal array by a constant + public ArrayMaths over(Short constant){ + short constantl = constant.shortValue(); + return this.over(constantl); + } + + + // divide the elements of the internal array by a constant + public ArrayMaths over(BigDecimal constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13:BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].divide(constant, BigDecimal.ROUND_HALF_UP)); + am.type = 12; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].over(constant.doubleValue())); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].over(new Phasor(constant.doubleValue()))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a BigDecimal cannot be divided by a char"); + case 17: throw new IllegalArgumentException("a BigDecimal cannot be divided by a Character"); + case 18: throw new IllegalArgumentException("a BigDecimal cannot be divided by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // divide the elements of the internal array by a constant + public ArrayMaths over(byte constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + + switch(this.type){ + case 0: + case 1: + case 2: + case 3: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i]/(double)constant)); + am.type = 0; + break; + case 4: long max = this.getMaximum_as_long(); + long[] ll = this.getArray_as_long(); + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i]/(long)constant)); + am.type = 4; + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11:byte maxi = this.getMaximum_as_byte(); + byte[] lll = this.getArray_as_byte(); + for(int i=0; i<this.length; i++)am.array.add(new Double((double)lll[i]/(double)constant)); + am.type = 0; + break; + case 12: for(int i=0; i<this.length; i++){ + BigDecimal hold1 = (BigDecimal)(this.array.get(i)); + hold1 = hold1.divide(new BigDecimal((double)constant), BigDecimal.ROUND_HALF_UP); + am.array.add(hold1); + hold1 = null; + } + am.type = 12; + break; + case 13: for(int i=0; i<this.length; i++){ + BigInteger hold1 = (BigInteger)(this.array.get(i)); + BigInteger hold2 = hold1.divide(new BigInteger((Integer.toString((int)constant)))); + am.array.add(hold2); + hold1 = null; + hold2 = null; + } + am.type = 13; + break; + case 14: for(int i=0; i<this.length; i++)am.array.add(((Complex)this.array.get(i)).over((double)constant)); + am.type = this.type; + break; + case 15: for(int i=0; i<this.length; i++)am.array.add(((Phasor)this.array.get(i)).over(new Phasor((double)constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a byte cannot be divided by a char"); + case 17: throw new IllegalArgumentException("a byte cannot be divided by a Character"); + case 18: throw new IllegalArgumentException("a byte cannot be divided by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // divide the elements of the internal array by a constant + public ArrayMaths over(Byte constant){ + byte constantl = constant.byteValue(); + return this.over(constantl); + } + + // divide the elements of the internal array by a constant + public ArrayMaths over(BigInteger constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 12: BigDecimal constantBD = Conv.convert_BigInteger_to_BigDecimal(constant); + BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].add(constantBD)); + am.type = 12; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 13:BigInteger[] bi = this.getArray_as_BigInteger(); + for(int i=0; i<this.length; i++)am.array.add(bi[i].divide(constant)); + am.type = 13; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].over(Conv.convert_BigInteger_to_double(constant))); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].over(new Phasor(Conv.convert_BigInteger_to_double(constant)))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a BigInteger cannot be divided by a char"); + case 17: throw new IllegalArgumentException("a BigInteger cannot be divided by a Character"); + case 18: throw new IllegalArgumentException("a BigInteger cannot be divided by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // divide the elements of the internal array by a constant + public ArrayMaths over(Complex constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].over(constant)); + am.type = 14; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].over(Conv.convert_Complex_to_Phasor(constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a Complex cannot be divided by a char"); + case 17: throw new IllegalArgumentException("a Complex cannot be divided by a Character"); + case 18: throw new IllegalArgumentException("a Complex cannot be divided by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + // divide the elements of the internal array by a constant + public ArrayMaths over(Phasor constant){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].over(constant)); + am.type = 15; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].over(Conv.convert_Phasor_to_Complex(constant))); + am.type = this.type; + break; + case 16: throw new IllegalArgumentException("a Phasor cannot be divided by a char"); + case 17: throw new IllegalArgumentException("a Phasor cannot be divided by a Character"); + case 18: throw new IllegalArgumentException("a Phasor cannot be divided by a String"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + // TRUNCATION AND ROUNDING OF ARRAY ELEMENTS + // Returns new ArrayMaths with array elements truncated to n decimal places + public ArrayMaths truncate(int n){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1:double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Fmath.truncate(dd[i], n))); + am.type = this.type; + break; + case 2: + case 3:float[] ff = this.getArray_as_float(); + for(int i=0; i<this.length; i++)am.array.add(new Float(Fmath.truncate(ff[i], n))); + am.type = this.type; + break; + case 4: + case 5:long[] ll = this.getArray_as_long(); + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i])); + am.type = this.type; + break; + case 6: + case 7:int[] ii = this.getArray_as_int(); + for(int i=0; i<this.length; i++)am.array.add(new Long(ii[i])); + am.type = this.type; + break; + case 8: + case 9:short[] ss = this.getArray_as_short(); + for(int i=0; i<this.length; i++)am.array.add(new Short(ss[i])); + am.type = this.type; + break; + case 10: + case 11:byte[] bb = this.getArray_as_byte(); + for(int i=0; i<this.length; i++)am.array.add(new Byte(bb[i])); + am.type = this.type; + break; + case 12:BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].setScale(n, BigDecimal.ROUND_HALF_UP)); + am.type = this.type; + break; + case 13:BigInteger[] bi = this.getArray_as_BigInteger(); + for(int i=0; i<this.length; i++)am.array.add(bi[i]); + am.type = this.type; + break; + case 14:Complex[] co = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(Complex.truncate(co[i], n)); + am.type = this.type; + break; + case 15:Phasor[] ph = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(Phasor.truncate(ph[i], n)); + am.type = this.type; + break; + case 16: + case 17:char[] ch = this.getArray_as_char(); + for(int i=0; i<this.length; i++)am.array.add(new Character(ch[i])); + am.type = this.type; + break; + case 18: String[] st = this.getArray_as_String(); + for(int i=0; i<this.length; i++)am.array.add(st[i]); + am.type = this.type; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + Conv.restoreMessages(); + return am; + } + + + // Returns new ArrayMaths with array elements rounded down to the nearest lower integer + public ArrayMaths floor(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1:double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Math.floor(dd[i]))); + am.type = this.type; + break; + case 2: + case 3:float[] ff = this.getArray_as_float(); + for(int i=0; i<this.length; i++)am.array.add(new Float(Math.floor(ff[i]))); + am.type = this.type; + break; + case 4: + case 5:long[] ll = this.getArray_as_long(); + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i])); + am.type = this.type; + break; + case 6: + case 7:int[] ii = this.getArray_as_int(); + for(int i=0; i<this.length; i++)am.array.add(new Long(ii[i])); + am.type = this.type; + break; + case 8: + case 9:short[] ss = this.getArray_as_short(); + for(int i=0; i<this.length; i++)am.array.add(new Short(ss[i])); + am.type = this.type; + break; + case 10: + case 11:byte[] bb = this.getArray_as_byte(); + for(int i=0; i<this.length; i++)am.array.add(new Byte(bb[i])); + am.type = this.type; + break; + case 12:BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].setScale(0, BigDecimal.ROUND_DOWN)); + am.type = this.type; + break; + case 13:BigInteger[] bi = this.getArray_as_BigInteger(); + for(int i=0; i<this.length; i++)am.array.add(bi[i]); + am.type = this.type; + break; + case 14:Complex[] co = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(new Complex(Math.floor(co[i].getReal()), Math.floor(co[i].getImag()))); + am.type = this.type; + break; + case 15:Phasor[] ph = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(new Phasor(Math.floor(ph[i].getMagnitude()), Math.floor(ph[i].getPhaseInDegrees()))); + am.type = this.type; + break; + case 16: + case 17:char[] ch = this.getArray_as_char(); + for(int i=0; i<this.length; i++)am.array.add(new Character(ch[i])); + am.type = this.type; + break; + case 18: String[] st = this.getArray_as_String(); + for(int i=0; i<this.length; i++)am.array.add(st[i]); + am.type = this.type; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + Conv.restoreMessages(); + return am; + } + + + // Returns new ArrayMaths with array elements rounded up to the nearest higher integer + public ArrayMaths ceil(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1:double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Math.ceil(dd[i]))); + am.type = this.type; + break; + case 2: + case 3:float[] ff = this.getArray_as_float(); + for(int i=0; i<this.length; i++)am.array.add(new Float(Math.ceil(ff[i]))); + am.type = this.type; + break; + case 4: + case 5:long[] ll = this.getArray_as_long(); + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i])); + am.type = this.type; + break; + case 6: + case 7:int[] ii = this.getArray_as_int(); + for(int i=0; i<this.length; i++)am.array.add(new Long(ii[i])); + am.type = this.type; + break; + case 8: + case 9:short[] ss = this.getArray_as_short(); + for(int i=0; i<this.length; i++)am.array.add(new Short(ss[i])); + am.type = this.type; + break; + case 10: + case 11:byte[] bb = this.getArray_as_byte(); + for(int i=0; i<this.length; i++)am.array.add(new Byte(bb[i])); + am.type = this.type; + break; + case 12:BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].setScale(0, BigDecimal.ROUND_UP)); + am.type = this.type; + break; + case 13:BigInteger[] bi = this.getArray_as_BigInteger(); + for(int i=0; i<this.length; i++)am.array.add(bi[i]); + am.type = this.type; + break; + case 14:Complex[] co = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(new Complex(Math.ceil(co[i].getReal()), Math.ceil(co[i].getImag()))); + am.type = this.type; + break; + case 15:Phasor[] ph = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(new Phasor(Math.ceil(ph[i].getMagnitude()), Math.ceil(ph[i].getPhaseInDegrees()))); + am.type = this.type; + break; + case 16: + case 17:char[] ch = this.getArray_as_char(); + for(int i=0; i<this.length; i++)am.array.add(new Character(ch[i])); + am.type = this.type; + break; + case 18: String[] st = this.getArray_as_String(); + for(int i=0; i<this.length; i++)am.array.add(st[i]); + am.type = this.type; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + Conv.restoreMessages(); + return am; + } + + + // Returns new ArrayMaths with array elements rounded to a value that is closest in value to the element and is equal to a mathematical integer. + public ArrayMaths rint(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1:double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Math.rint(dd[i]))); + am.type = this.type; + break; + case 2: + case 3:float[] ff = this.getArray_as_float(); + for(int i=0; i<this.length; i++)am.array.add(new Float(Math.rint(ff[i]))); + am.type = this.type; + break; + case 4: + case 5:long[] ll = this.getArray_as_long(); + for(int i=0; i<this.length; i++)am.array.add(new Long(ll[i])); + am.type = this.type; + break; + case 6: + case 7:int[] ii = this.getArray_as_int(); + for(int i=0; i<this.length; i++)am.array.add(new Long(ii[i])); + am.type = this.type; + break; + case 8: + case 9:short[] ss = this.getArray_as_short(); + for(int i=0; i<this.length; i++)am.array.add(new Short(ss[i])); + am.type = this.type; + break; + case 10: + case 11:byte[] bb = this.getArray_as_byte(); + for(int i=0; i<this.length; i++)am.array.add(new Byte(bb[i])); + am.type = this.type; + break; + case 12:BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].setScale(0, BigDecimal.ROUND_HALF_EVEN)); + am.type = this.type; + break; + case 13:BigInteger[] bi = this.getArray_as_BigInteger(); + for(int i=0; i<this.length; i++)am.array.add(bi[i]); + am.type = this.type; + break; + case 14:Complex[] co = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(new Complex(Math.rint(co[i].getReal()), Math.rint(co[i].getImag()))); + am.type = this.type; + break; + case 15:Phasor[] ph = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(new Phasor(Math.rint(ph[i].getMagnitude()), Math.rint(ph[i].getPhaseInDegrees()))); + am.type = this.type; + break; + case 16: + case 17:char[] ch = this.getArray_as_char(); + for(int i=0; i<this.length; i++)am.array.add(new Character(ch[i])); + am.type = this.type; + break; + case 18: String[] st = this.getArray_as_String(); + for(int i=0; i<this.length; i++)am.array.add(st[i]); + am.type = this.type; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + Conv.restoreMessages(); + return am; + } + + + // ARRAY REVERSAL + // Returns new ArrayMaths with array elements reversed + public ArrayMaths reverse(){ + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + am.type = this.type; + am.sortedIndices = new int[this.length]; + + for(int i=0; i<this.length; i++){ + am.array.add(this.array.get(this.length - i - 1)); + am.sortedIndices[i] = this.length - i - 1; + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + return am; + } + + + // ARRAY LOGARITHMS + // Returns new ArrayMaths with array elements converted to their natural logs + public ArrayMaths log(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 17: + case 18: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Math.log(dd[i]))); + am.type = 1; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(Complex.log(cc[i])); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(Phasor.log(pp[i])); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // Returns new ArrayMaths with array elements converted to log to the base 2 + public ArrayMaths log2(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 17: + case 18: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Fmath.log2(dd[i]))); + am.type = 1; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(Complex.log(cc[i].over(Math.log(2.0)))); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(Phasor.log(pp[i].over(Math.log(2.0)))); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // Returns new ArrayMaths with array elements converted to log10(array element) + public ArrayMaths log10(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 17: + case 18: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Math.log10(dd[i]))); + am.type = 1; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(Complex.log(cc[i].over(Math.log(10.0)))); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(Phasor.log(pp[i].over(Math.log(10)))); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + // Returns new ArrayMaths with array elements converted to antilog10(element) + public ArrayMaths antilog10(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 17: + case 18: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Math.pow(10.0, dd[i]))); + am.type = 1; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(Complex.pow(10.0, cc[i])); + am.type = this.type; + break; + case 15: Complex[] pp = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(Conv.convert_Complex_to_Phasor(Complex.pow(10.0, pp[i]))); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // Returns new ArrayMaths with array elements, x, converted to x.log2(x) + public ArrayMaths xLog2x(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 17: + case 18: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i]*Fmath.log2(dd[i]))); + am.type = 1; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].times(Complex.log(cc[i].over(Math.log(2))))); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].times(Phasor.log(pp[i].over(Math.log(2))))); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // Returns new ArrayMaths with array elements, x, converted to x.loge(x) + public ArrayMaths xLogEx(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 17: + case 18: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i]*Math.log(dd[i]))); + am.type = 1; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].times(Complex.log(cc[i]))); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].times(Phasor.log(pp[i]))); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // Returns new ArrayMaths with array elements, x, converted to x.log10(x) + public ArrayMaths xLog10x(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 17: + case 18: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(dd[i]*Math.log10(dd[i]))); + am.type = 1; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].times(Complex.log(cc[i].over(Math.log(10))))); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].times(Phasor.log(pp[i].over(Math.log(10))))); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // Returns new ArrayMaths with array elements, x, converted to -x.log2(x) + public ArrayMaths minusxLog2x(){ + ArrayMaths am = this.xLog2x(); + return am.negate(); + } + + // Returns new ArrayMaths with array elements, x, converted to -x.loge(x) + public ArrayMaths minusxLogEx(){ + ArrayMaths am = this.xLogEx(); + return am.negate(); + } + + // Returns new ArrayMaths with array elements, x, converted to -x.log10(x) + public ArrayMaths minusxLog10x(){ + ArrayMaths am = this.xLog10x(); + return am.negate(); + } + + // SQUARE ROOTS + // Returns new ArrayMaths with array elements converted to their square roots + public ArrayMaths sqrt(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 17: + case 18: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Math.sqrt(dd[i]))); + am.type = 1; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(Complex.sqrt(cc[i])); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(Phasor.sqrt(pp[i])); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // Returns new ArrayMaths with array elements converted to 1.0/sqrt(element) + public ArrayMaths oneOverSqrt(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 17: + case 18: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(1.0D/Math.sqrt(dd[i]))); + am.type = 1; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add((Complex.sqrt(cc[i])).inverse()); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add((Phasor.sqrt(pp[i])).inverse()); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // VARIOUS TRANSFORMATION OF ARRAY ELEMENTS + // Returns new ArrayMaths with array elements converted to their absolute values + public ArrayMaths abs(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Math.abs(dd[i]))); + am.type = this.type; + break; + case 2: + case 3: float[] ff = this.getArray_as_float(); + for(int i=0; i<this.length; i++)am.array.add(new Float(Math.abs(ff[i]))); + am.type = this.type; + break; + case 4: + case 5: long[] ll = this.getArray_as_long(); + for(int i=0; i<this.length; i++)am.array.add(new Long(Math.abs(ll[i]))); + am.type = this.type; + break; + case 6: + case 7: int[] ii1 = this.getArray_as_int(); + for(int i=0; i<this.length; i++)am.array.add(new Integer(Math.abs(ii1[i]))); + am.type = this.type; + break; + case 8: + case 9: int[] ii2 = this.getArray_as_int(); + for(int i=0; i<this.length; i++)am.array.add(new Short((short)Math.abs(ii2[i]))); + am.type = this.type; + break; + case 10: + case 11: int[] ii3 = this.getArray_as_int(); + for(int i=0; i<this.length; i++)am.array.add(new Byte((byte)Math.abs(ii3[i]))); + am.type = this.type; + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].abs()); + am.type = this.type; + break; + case 13: BigInteger[] bi = this.getArray_as_BigInteger(); + for(int i=0; i<this.length; i++)am.array.add(bi[i].abs()); + am.type = this.type; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(Complex.abs(cc[i])); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].abs()); + am.type = 15; + break; + case 16: + case 17: int[] ii4 = this.getArray_as_int(); + for(int i=0; i<this.length; i++)am.array.add(new Integer(Math.abs(ii4[i]))); + am.type = this.type; + break; + case 18: double[] dd2 = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Math.abs(dd2[i]))); + am.type = 1; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + + // Returns new ArrayMaths with array elements converted to exp(element) + public ArrayMaths exp(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 17: + case 18: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Math.exp(dd[i]))); + am.type = 1; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(Complex.exp(cc[i])); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(Phasor.exp(pp[i])); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // Returns new ArrayMaths with array elements converted to 1.0/element + public ArrayMaths invert(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: + case 18: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(1.0D/dd[i])); + am.type = 1; + break; + case 12: + case 13: BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add((BigDecimal.ONE).divide(bd[i], BigDecimal.ROUND_HALF_UP)); + am.type = 12; + bd = null; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add((Complex.plusOne()).over(cc[i])); + am.type = 14; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add((Phasor.plusOne()).over(pp[i])); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + + // Returns new ArrayMaths with array elements raised to a power n + public ArrayMaths pow(int n){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: + case 18: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Math.pow(dd[i], n))); + am.type = 1; + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal bdpow = BigDecimal.ONE; + for(int i=0; i<this.length; i++){ + for(int j=0; j<n; j++)bdpow = bdpow.multiply(bd[i]); + am.array.add(bdpow); + } + bd = null; + bdpow = null; + am.type = 12; + break; + case 13: BigInteger[] bi = this.getArray_as_BigInteger(); + for(int i=0; i<this.length; i++)am.array.add(bi[i].pow(n)); + am.type = 13; + bi = null; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(Complex.pow(cc[i], n)); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(Phasor.pow(pp[i], n)); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + Conv.restoreMessages(); + return am; + } + + // Returns new ArrayMaths with array elements raised to a power n + public ArrayMaths pow(double n){ + if(this.suppressMessages)Conv.suppressMessages(); + + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 17: + case 18: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Math.pow(dd[i], n))); + am.type = 1; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(Complex.pow(cc[i], n)); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(Phasor.pow(pp[i], n)); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + Conv.restoreMessages(); + return am; + } + + // Returns new ArrayMaths with array elements raised to a power n + public ArrayMaths pow(float n){ + double nn = (double)n; + return this.pow(nn); + } + + // Returns new ArrayMaths with array elements raised to a power n + public ArrayMaths pow(long n){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: + case 18: double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(Math.pow(dd[i], n))); + am.type = 1; + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal bdpow = BigDecimal.ONE; + for(int i=0; i<this.length; i++){ + long j = 0L; + while(j<n){ + bdpow = bdpow.multiply(bd[i]); + } + am.array.add(bdpow); + } + bd = null; + bdpow = null; + am.type = 12; + break; + case 13: BigInteger[] bi = this.getArray_as_BigInteger(); + BigInteger bipow = BigInteger.ONE; + for(int i=0; i<this.length; i++){ + long j = 0L; + while(j<n){ + bipow = bipow.multiply(bi[i]); + } + am.array.add(bipow); + } + bi = null; + bipow = null; + am.type = 13; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(Complex.pow(cc[i], n)); + am.type = this.type; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(Phasor.pow(pp[i], n)); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + Conv.restoreMessages(); + return am; + } + + // Returns new ArrayMaths with array elements raised to a power n + public ArrayMaths pow(short n){ + int ii = (int)n; + return this.pow(ii); + } + + // Returns new ArrayMaths with array elements raised to a power n + public ArrayMaths pow(byte n){ + int ii = n; + return this.pow(ii); + } + + // Returns new ArrayMaths with array elements raised to a power n + public ArrayMaths pow(Number n){ + boolean test = integers.containsKey(n.getClass()); + if(test){ + if(n instanceof Long){ + return this.pow(n.longValue()); + } + else{ + if(n instanceof BigInteger){ + return this.pow(n.doubleValue()); + } + else{ + return this.pow(n.intValue()); + } + } + } + else{ + return this.pow(n.doubleValue()); + } + } + + // Returns new ArrayMaths with array elements converted to -element + public ArrayMaths negate(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + switch(this.type){ + case 0: + case 1: + case 16: + case 17: + case 18:double[] dd = this.getArray_as_double(); + for(int i=0; i<this.length; i++)am.array.add(new Double(-dd[i])); + am.type = 1; + break; + case 2: + case 3: float[] ff = this.getArray_as_float(); + for(int i=0; i<this.length; i++)am.array.add(new Float(-ff[i])); + am.type = 3; + break; + case 4: + case 5: long[] ll = this.getArray_as_long(); + for(int i=0; i<this.length; i++)am.array.add(new Long(-ll[i])); + am.type = 5; + break; + case 6: + case 7: int[] ii = this.getArray_as_int(); + for(int i=0; i<this.length; i++)am.array.add(new Integer(-ii[i])); + am.type = 7; + break; + case 8: + case 9: short[] ss = this.getArray_as_short(); + for(int i=0; i<this.length; i++)am.array.add(new Short((short)(-ss[i]))); + am.type = 9; + break; + case 10: + case 11: byte[] bb = this.getArray_as_byte(); + for(int i=0; i<this.length; i++)am.array.add(new Byte((byte)(-bb[i]))); + am.type = 11; + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + for(int i=0; i<this.length; i++)am.array.add(bd[i].negate()); + am.type = 12; + bd = null; + break; + case 13: BigInteger[] bi = this.getArray_as_BigInteger(); + for(int i=0; i<this.length; i++)am.array.add(bi[i].negate()); + am.type = 13; + bi = null; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + for(int i=0; i<this.length; i++)am.array.add(cc[i].negate()); + am.type = 14; + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + for(int i=0; i<this.length; i++)am.array.add(pp[i].negate()); + am.type = 15; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + Conv.restoreMessages(); + return am; + } + + + + // protected method for calcuating the sum of the array elements + // called by the public methods + protected void calcSum(){ + if(this.suppressMessages)Conv.suppressMessages(); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: double[] dd = this.getArray_as_double(); + double sum = 0.0D; + for(int i=0; i<this.length; i++)sum += dd[i]; + this.summ.add(new Double(sum)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17:long[] ll = this.getArray_as_long(); + long suml = 0L; + boolean test = false; + for(int i=0; i<this.length; i++){ + if(Long.MAX_VALUE-suml<ll[i])test=true; + suml += ll[i]; + } + if(test){ + double[] dd2 = this.getArray_as_double(); + double sum2 = 0.0D; + for(int i=0; i<this.length; i++)sum2 += dd2[i]; + this.summ.add(new Double(sum2)); + this.sumlongToDouble = true; + } + else{ + this.summ.add(new Long(suml)); + } + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal sumbd = new BigDecimal(0.0D); + for(int i=0; i<this.length; i++)sumbd.add(bd[i]); + this.summ.add(sumbd); + bd = null; + sumbd = null; + break; + case 13: BigInteger[] bi = this.getArray_as_BigInteger(); + BigInteger sumbi = BigInteger.ZERO; + for(int i=0; i<this.length; i++)sumbi.add(bi[i]); + this.summ.add(sumbi); + bi = null; + sumbi = null; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + Complex sumcc = Complex.zero(); + for(int i=0; i<this.length; i++)sumcc.plus(cc[i]); + this.summ.add(sumcc); + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + Phasor sumpp = Phasor.zero(); + for(int i=0; i<this.length; i++)sumpp.plus(pp[i]); + this.summ.add(sumpp); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + this.sumDone = true; + Conv.restoreMessages(); + } + + + // returns the sum of the array elements as a double + public double sum(){ + return this.getSum_as_double(); + } + + public double sum_as_double(){ + return this.getSum_as_double(); + } + + public double getSum(){ + return this.getSum_as_double(); + } + + public double getSum_as_double(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + double sum = 0.0D; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = ((Double)this.summ.get(0)).doubleValue(); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = ((Double)this.summ.get(0)).doubleValue(); + } + else{ + sum = Conv.convert_Long_to_double((Long)this.summ.get(0)); + } + break; + case 12: sum = Conv.convert_BigDecimal_to_double((BigDecimal)this.summ.get(0)); + break; + case 13: sum = Conv.convert_BigInteger_to_double((BigInteger)this.summ.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as double is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + // returns the sum of the array elements as a Double + public Double sum_as_Double(){ + return this.getSum_as_Double(); + } + + public Double getSum_as_Double(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + Double sum = new Double(0.0D); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = (Double)this.summ.get(0); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = (Double)this.summ.get(0); + } + else{ + sum = Conv.convert_Long_to_Double((Long)this.summ.get(0)); + } + break; + case 12: sum = Conv.convert_BigDecimal_to_Double((BigDecimal)this.summ.get(0)); + break; + case 13: sum = Conv.convert_BigInteger_to_Double((BigInteger)this.summ.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as Double is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + // returns the sum of the array elements as a float + public float sum_as_float(){ + return this.getSum_as_float(); + } + + public float getSum_as_float(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + float sum = 0.0F; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = Conv.convert_Double_to_float((Double)this.summ.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = Conv.convert_Double_to_float((Double)this.summ.get(0)); + } + else{ + sum = Conv.convert_Long_to_float((Long)this.summ.get(0)); + } + break; + case 12: sum = Conv.convert_BigDecimal_to_float((BigDecimal)this.summ.get(0)); + break; + case 13: sum = Conv.convert_BigInteger_to_float((BigInteger)this.summ.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as float is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + // returns the sum of the array elements as a Float + public Float sum_as_Float(){ + return this.getSum_as_Float(); + } + + public Float getSum_as_Float(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + Float sum = new Float(0.0F); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = Conv.convert_Double_to_Float((Double)this.summ.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = Conv.convert_Double_to_Float((Double)this.summ.get(0)); + } + else{ + sum = Conv.convert_Long_to_Float((Long)this.summ.get(0)); + } + break; + case 12: sum = Conv.convert_BigDecimal_to_Float((BigDecimal)this.summ.get(0)); + break; + case 13: sum = Conv.convert_BigInteger_to_Float((BigInteger)this.summ.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as Float is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + + // returns the sum of the array elements as a long + public long sum_as_long(){ + return this.getSum_as_long(); + } + + public long getSum_as_long(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + long sum = 0L; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = Conv.convert_Double_to_long((Double)this.summ.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = Conv.convert_Double_to_long((Double)this.summ.get(0)); + } + else{ + sum = (Long)this.summ.get(0); + } + break; + case 12: sum = Conv.convert_BigDecimal_to_long((BigDecimal)this.summ.get(0)); + break; + case 13: sum = Conv.convert_BigInteger_to_long((BigInteger)this.summ.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as long is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + // returns the sum of the array elements as a Long + public Long sum_as_Long(){ + return this.getSum_as_Long(); + } + + public Long getSum_as_Long(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + Long sum = new Long(0L); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = Conv.convert_Double_to_Long((Double)this.summ.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = Conv.convert_Double_to_Long((Double)this.summ.get(0)); + } + else{ + sum = (Long)this.summ.get(0); + } + break; + case 12: sum = Conv.convert_BigDecimal_to_Long((BigDecimal)this.summ.get(0)); + break; + case 13: sum = Conv.convert_BigInteger_to_Long((BigInteger)this.summ.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as Long is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + + // returns the sum of the array elements as an int + public int sum_as_int(){ + return this.getSum_as_int(); + } + + public int getSum_as_int(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + int sum = 0; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = Conv.convert_Double_to_int((Double)this.summ.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = Conv.convert_Double_to_int((Double)this.summ.get(0)); + } + else{ + sum = Conv.convert_Long_to_int((Long)this.summ.get(0)); + } + break; + case 12: sum = Conv.convert_BigDecimal_to_int((BigDecimal)this.summ.get(0)); + break; + case 13: sum = Conv.convert_BigInteger_to_int((BigInteger)this.summ.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as int is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + // returns the sum of the array elements as an Integer + public Integer sum_as_Integer(){ + return this.getSum_as_Integer(); + } + + public Integer getSum_as_Integer(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + Integer sum = new Integer(0); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = Conv.convert_Double_to_Integer((Double)this.summ.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = Conv.convert_Double_to_Integer((Double)this.summ.get(0)); + } + else{ + sum = Conv.convert_Long_to_Integer((Long)this.summ.get(0)); + } + break; + case 12: sum = Conv.convert_BigDecimal_to_Integer((BigDecimal)this.summ.get(0)); + break; + case 13: sum = Conv.convert_BigInteger_to_Integer((BigInteger)this.summ.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as Integer is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + // returns the sum of the array elements as a short + public short sum_as_short(){ + return this.getSum_as_short(); + } + + public short getSum_as_short(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + short sum = 0; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = Conv.convert_Double_to_short((Double)this.summ.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = Conv.convert_Double_to_short((Double)this.summ.get(0)); + } + else{ + sum = Conv.convert_Long_to_short((Long)this.summ.get(0)); + } + break; + case 12: sum = Conv.convert_BigDecimal_to_short((BigDecimal)this.summ.get(0)); + break; + case 13: sum = Conv.convert_BigInteger_to_short((BigInteger)this.summ.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as short is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + // returns the sum of the array elements as a Short + public Short sum_as_Short(){ + return this.getSum_as_Short(); + } + + public Short getSum_as_Short(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + Short sum = new Short((short)0); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = Conv.convert_Double_to_Short((Double)this.summ.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = Conv.convert_Double_to_Short((Double)this.summ.get(0)); + } + else{ + sum = Conv.convert_Long_to_Short((Long)this.summ.get(0)); + } + break; + case 12: sum = Conv.convert_BigDecimal_to_Short((BigDecimal)this.summ.get(0)); + break; + case 13: sum = Conv.convert_BigInteger_to_Short((BigInteger)this.summ.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as Short is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + + // returns the sum of the array elements as a byte + public byte sum_as_byte(){ + return this.getSum_as_byte(); + } + + public byte getSum_as_byte(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + byte sum = 0; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = Conv.convert_Double_to_byte((Double)this.summ.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = Conv.convert_Double_to_byte((Double)this.summ.get(0)); + } + else{ + sum = Conv.convert_Long_to_byte((Long)this.summ.get(0)); + } + break; + case 12: sum = Conv.convert_BigDecimal_to_byte((BigDecimal)this.summ.get(0)); + break; + case 13: sum = Conv.convert_BigInteger_to_byte((BigInteger)this.summ.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as byte is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + // returns the sum of the array elements as a Byte + public Byte sum_as_Byte(){ + return this.getSum_as_Byte(); + } + + public Byte getSum_as_Byte(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + Byte sum = new Byte((byte)0); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = Conv.convert_Double_to_Byte((Double)this.summ.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = Conv.convert_Double_to_Byte((Double)this.summ.get(0)); + } + else{ + sum = Conv.convert_Long_to_Byte((Long)this.summ.get(0)); + } + break; + case 12: sum = Conv.convert_BigDecimal_to_Byte((BigDecimal)this.summ.get(0)); + break; + case 13: sum = Conv.convert_BigInteger_to_Byte((BigInteger)this.summ.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as Byte is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + + // returns the sum of the array elements as a BigDecimal + public BigDecimal sum_as_BigDecimal(){ + return this.getSum_as_BigDecimal(); + } + + public BigDecimal getSum_as_BigDecimal(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + BigDecimal sum = new BigDecimal(0.0D); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = Conv.convert_Double_to_BigDecimal((Double)this.summ.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = Conv.convert_Double_to_BigDecimal((Double)this.summ.get(0)); + } + else{ + sum = Conv.convert_Long_to_BigDecimal((Long)this.summ.get(0)); + } + break; + case 12: sum = (BigDecimal)this.summ.get(0); + break; + case 13: sum = Conv.convert_BigInteger_to_BigDecimal((BigInteger)this.summ.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as BigDecimal is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + // returns the sum of the array elements as a BigInteger + public BigInteger sum_as_BigInteger(){ + return this.getSum_as_BigInteger(); + } + + public BigInteger getSum_as_BigInteger(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + BigInteger sum = BigInteger.ZERO; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = Conv.convert_Double_to_BigInteger((Double)this.summ.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = Conv.convert_Double_to_BigInteger((Double)this.summ.get(0)); + } + else{ + sum = Conv.convert_Long_to_BigInteger((Long)this.summ.get(0)); + } + break; + case 12: sum = Conv.convert_BigDecimal_to_BigInteger((BigDecimal)this.summ.get(0)); + break; + case 13: sum = (BigInteger)this.summ.get(0); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as BigInteger is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + + // returns the sum of the array elements as a Complex + public Complex sum_as_Complex(){ + return this.getSum_as_Complex(); + } + + public Complex getSum_as_Complex(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + Complex sum = Complex.zero(); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = new Complex(((Double)this.summ.get(0)).doubleValue()); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = new Complex(((Double)this.summ.get(0)).doubleValue()); + } + else{ + sum = new Complex(((Long)this.summ.get(0)).doubleValue()); + } + break; + case 12: sum = new Complex(((BigDecimal)this.summ.get(0)).doubleValue()); + break; + case 13: sum = new Complex(((BigInteger)this.summ.get(0)).doubleValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as Complex is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + + // returns the sum of the array elements as a Phasor + public Phasor sum_as_Phasor(){ + return this.getSum_as_Phasor(); + } + + public Phasor getSum_as_Phasor(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + Phasor sum = Phasor.zero(); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = new Phasor(((Double)this.summ.get(0)).doubleValue()); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = new Phasor(((Double)this.summ.get(0)).doubleValue()); + } + else{ + sum = new Phasor(((Long)this.summ.get(0)).doubleValue()); + } + break; + case 12: sum = new Phasor(((BigDecimal)this.summ.get(0)).doubleValue()); + break; + case 13: sum = new Phasor(((BigInteger)this.summ.get(0)).doubleValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as Phasor is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + // returns the sum of the array elements as a String + public String sum_as_String(){ + return this.getSum_as_String(); + } + + public String getSum_as_String(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.sumDone)this.calcSum(); + String sum = " "; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: sum = Double.toString(((Double)this.summ.get(0)).doubleValue()); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.sumlongToDouble){ + sum = Double.toString(((Double)this.summ.get(0)).doubleValue()); + } + else{ + sum = Double.toString(((Long)this.summ.get(0)).doubleValue()); + } + break; + case 12: sum = ((BigDecimal)this.summ.get(0)).toString(); + break; + case 13: sum = ((BigInteger)this.summ.get(0)).toString(); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a sum as String is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return sum; + } + + // protected method for calcuating the product of the array elements + // called by the public methods + protected void calcProduct(){ + if(this.suppressMessages)Conv.suppressMessages(); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: double[] dd = this.getArray_as_double(); + double product= 1.0D; + for(int i=0; i<this.length; i++)product*= dd[i]; + this.productt.add(new Double(product)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17:long[] ll = this.getArray_as_long(); + long productl = 1L; + boolean test = false; + for(int i=0; i<this.length; i++){ + if(Long.MAX_VALUE/productl<ll[i])test=true; + productl += ll[i]; + } + if(test){ + double[] dd2 = this.getArray_as_double(); + double product2 = 1.0D; + for(int i=0; i<this.length; i++)product2 *= dd2[i]; + this.productt.add(new Double(product2)); + this.sumlongToDouble = true; + } + else{ + this.productt.add(new Long(productl)); + } + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + BigDecimal productbd = new BigDecimal(1.0D); + for(int i=0; i<this.length; i++)productbd.multiply(bd[i]); + this.productt.add(productbd); + bd = null; + productbd = null; + break; + case 13: BigInteger[] bi = this.getArray_as_BigInteger(); + BigInteger productbi = BigInteger.ONE; + for(int i=0; i<this.length; i++)productbi.multiply(bi[i]); + this.productt.add(productbi); + bi = null; + productbi = null; + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + Complex productcc = Complex.plusOne(); + for(int i=0; i<this.length; i++)productcc.times(cc[i]); + this.productt.add(productcc); + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + Phasor productpp = Phasor.plusOne(); + for(int i=0; i<this.length; i++)productpp.times(pp[i]); + this.productt.add(productpp); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + this.productDone = true; + Conv.restoreMessages(); + } + + // returns the product of the array elements as a double + public double product(){ + return this.getProduct_as_double(); + } + + public double product_as_double(){ + return this.getProduct_as_double(); + } + + public double getProduct(){ + return this.getProduct_as_double(); + } + + public double getProduct_as_double(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + double product= 0.0D; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= ((Double)this.productt.get(0)).doubleValue(); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= ((Double)this.productt.get(0)).doubleValue(); + } + else{ + product= Conv.convert_Long_to_double((Long)this.productt.get(0)); + } + break; + case 12: product= Conv.convert_BigDecimal_to_double((BigDecimal)this.productt.get(0)); + break; + case 13: product= Conv.convert_BigInteger_to_double((BigInteger)this.productt.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas double is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + // returns the product of the array elements as a Double + public Double product_as_Double(){ + return this.getProduct_as_Double(); + } + + public Double getProduct_as_Double(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + Double product= new Double(0.0D); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= (Double)this.productt.get(0); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= (Double)this.productt.get(0); + } + else{ + product= Conv.convert_Long_to_Double((Long)this.productt.get(0)); + } + break; + case 12: product= Conv.convert_BigDecimal_to_Double((BigDecimal)this.productt.get(0)); + break; + case 13: product= Conv.convert_BigInteger_to_Double((BigInteger)this.productt.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas Double is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + + // returns the product of the array elements as a float + public float product_as_float(){ + return this.getProduct_as_float(); + } + + public float getProduct_as_float(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + float product= 0.0F; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= Conv.convert_Double_to_float((Double)this.productt.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= Conv.convert_Double_to_float((Double)this.productt.get(0)); + } + else{ + product= Conv.convert_Long_to_float((Long)this.productt.get(0)); + } + break; + case 12: product= Conv.convert_BigDecimal_to_float((BigDecimal)this.productt.get(0)); + break; + case 13: product= Conv.convert_BigInteger_to_float((BigInteger)this.productt.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas float is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + // returns the product of the array elements as a Float + public Float product_as_Float(){ + return this.getProduct_as_Float(); + } + + public Float getProduct_as_Float(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + Float product= new Float(0.0F); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= Conv.convert_Double_to_Float((Double)this.productt.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= Conv.convert_Double_to_Float((Double)this.productt.get(0)); + } + else{ + product= Conv.convert_Long_to_Float((Long)this.productt.get(0)); + } + break; + case 12: product= Conv.convert_BigDecimal_to_Float((BigDecimal)this.productt.get(0)); + break; + case 13: product= Conv.convert_BigInteger_to_Float((BigInteger)this.productt.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas Float is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + + // returns the product of the array elements as a long + public long product_as_long(){ + return this.getProduct_as_long(); + } + + public long getProduct_as_long(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + long product= 0L; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= Conv.convert_Double_to_long((Double)this.productt.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= Conv.convert_Double_to_long((Double)this.productt.get(0)); + } + else{ + product= (Long)this.productt.get(0); + } + break; + case 12: product= Conv.convert_BigDecimal_to_long((BigDecimal)this.productt.get(0)); + break; + case 13: product= Conv.convert_BigInteger_to_long((BigInteger)this.productt.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas long is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + // returns the product of the array elements as a Long + public Long product_as_Long(){ + return this.getProduct_as_Long(); + } + + public Long getProduct_as_Long(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + Long product= new Long(0L); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= Conv.convert_Double_to_Long((Double)this.productt.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= Conv.convert_Double_to_Long((Double)this.productt.get(0)); + } + else{ + product= (Long)this.productt.get(0); + } + break; + case 12: product= Conv.convert_BigDecimal_to_Long((BigDecimal)this.productt.get(0)); + break; + case 13: product= Conv.convert_BigInteger_to_Long((BigInteger)this.productt.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas Long is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + // returns the product of the array elements as an int + public int product_as_int(){ + return this.getProduct_as_int(); + } + + public int getProduct_as_int(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + int product= 0; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= Conv.convert_Double_to_int((Double)this.productt.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= Conv.convert_Double_to_int((Double)this.productt.get(0)); + } + else{ + product= Conv.convert_Long_to_int((Long)this.productt.get(0)); + } + break; + case 12: product= Conv.convert_BigDecimal_to_int((BigDecimal)this.productt.get(0)); + break; + case 13: product= Conv.convert_BigInteger_to_int((BigInteger)this.productt.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas int is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + // returns the product of the array elements as an Integer + public Integer product_as_Integer(){ + return this.getProduct_as_Integer(); + } + + public Integer getProduct_as_Integer(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + Integer product= new Integer(0); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= Conv.convert_Double_to_Integer((Double)this.productt.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= Conv.convert_Double_to_Integer((Double)this.productt.get(0)); + } + else{ + product= Conv.convert_Long_to_Integer((Long)this.productt.get(0)); + } + break; + case 12: product= Conv.convert_BigDecimal_to_Integer((BigDecimal)this.productt.get(0)); + break; + case 13: product= Conv.convert_BigInteger_to_Integer((BigInteger)this.productt.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas Integer is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + // returns the product of the array elements as a short + public short product_as_short(){ + return this.getProduct_as_short(); + } + + public short getProduct_as_short(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + short product= 0; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= Conv.convert_Double_to_short((Double)this.productt.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= Conv.convert_Double_to_short((Double)this.productt.get(0)); + } + else{ + product= Conv.convert_Long_to_short((Long)this.productt.get(0)); + } + break; + case 12: product= Conv.convert_BigDecimal_to_short((BigDecimal)this.productt.get(0)); + break; + case 13: product= Conv.convert_BigInteger_to_short((BigInteger)this.productt.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas short is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + // returns the product of the array elements as a Short + public Short product_as_Short(){ + return this.getProduct_as_Short(); + } + + public Short getProduct_as_Short(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + Short product= new Short((short)0); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= Conv.convert_Double_to_Short((Double)this.productt.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= Conv.convert_Double_to_Short((Double)this.productt.get(0)); + } + else{ + product= Conv.convert_Long_to_Short((Long)this.productt.get(0)); + } + break; + case 12: product= Conv.convert_BigDecimal_to_Short((BigDecimal)this.productt.get(0)); + break; + case 13: product= Conv.convert_BigInteger_to_Short((BigInteger)this.productt.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas Short is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + // returns the product of the array elements as a byte + public byte product_as_byte(){ + return this.getProduct_as_byte(); + } + + public byte getProduct_as_byte(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + byte product= 0; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= Conv.convert_Double_to_byte((Double)this.productt.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= Conv.convert_Double_to_byte((Double)this.productt.get(0)); + } + else{ + product= Conv.convert_Long_to_byte((Long)this.productt.get(0)); + } + break; + case 12: product= Conv.convert_BigDecimal_to_byte((BigDecimal)this.productt.get(0)); + break; + case 13: product= Conv.convert_BigInteger_to_byte((BigInteger)this.productt.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas byte is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + // returns the product of the array elements as a Byte + public Byte product_as_Byte(){ + return this.getProduct_as_Byte(); + } + + public Byte getProduct_as_Byte(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + Byte product= new Byte((byte)0); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= Conv.convert_Double_to_Byte((Double)this.productt.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= Conv.convert_Double_to_Byte((Double)this.productt.get(0)); + } + else{ + product= Conv.convert_Long_to_Byte((Long)this.productt.get(0)); + } + break; + case 12: product= Conv.convert_BigDecimal_to_Byte((BigDecimal)this.productt.get(0)); + break; + case 13: product= Conv.convert_BigInteger_to_Byte((BigInteger)this.productt.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas Byte is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + + // returns the product of the array elements as a BigDecimal + public BigDecimal product_as_BigDecimal(){ + return this.getProduct_as_BigDecimal(); + } + + public BigDecimal getProduct_as_BigDecimal(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + BigDecimal product= new BigDecimal(0.0D); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= Conv.convert_Double_to_BigDecimal((Double)this.productt.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= Conv.convert_Double_to_BigDecimal((Double)this.productt.get(0)); + } + else{ + product= Conv.convert_Long_to_BigDecimal((Long)this.productt.get(0)); + } + break; + case 12: product= (BigDecimal)this.productt.get(0); + break; + case 13: product= Conv.convert_BigInteger_to_BigDecimal((BigInteger)this.productt.get(0)); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas BigDecimal is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + // returns the product of the array elements as a BigInteger + public BigInteger product_as_BigInteger(){ + return this.getProduct_as_BigInteger(); + } + + public BigInteger getProduct_as_BigInteger(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + BigInteger product= BigInteger.ZERO; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= Conv.convert_Double_to_BigInteger((Double)this.productt.get(0)); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= Conv.convert_Double_to_BigInteger((Double)this.productt.get(0)); + } + else{ + product= Conv.convert_Long_to_BigInteger((Long)this.productt.get(0)); + } + break; + case 12: product= Conv.convert_BigDecimal_to_BigInteger((BigDecimal)this.productt.get(0)); + break; + case 13: product= (BigInteger)this.productt.get(0); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas BigInteger is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + // returns the product of the array elements as a Complex + public Complex product_as_Complex(){ + return this.getProduct_as_Complex(); + } + + public Complex getProduct_as_Complex(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + Complex product= Complex.zero(); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= new Complex(((Double)this.productt.get(0)).doubleValue()); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= new Complex(((Double)this.productt.get(0)).doubleValue()); + } + else{ + product= new Complex(((Long)this.productt.get(0)).doubleValue()); + } + break; + case 12: product= new Complex(((BigDecimal)this.productt.get(0)).doubleValue()); + break; + case 13: product= new Complex(((BigInteger)this.productt.get(0)).doubleValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas Complex is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + // returns the product of the array elements as a Phasor + public Phasor product_as_Phasor(){ + return this.getProduct_as_Phasor(); + } + + public Phasor getProduct_as_Phasor(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + Phasor product= Phasor.zero(); + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= new Phasor(((Double)this.productt.get(0)).doubleValue()); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= new Phasor(((Double)this.productt.get(0)).doubleValue()); + } + else{ + product= new Phasor(((Long)this.productt.get(0)).doubleValue()); + } + break; + case 12: product= new Phasor(((BigDecimal)this.productt.get(0)).doubleValue()); + break; + case 13: product= new Phasor(((BigInteger)this.productt.get(0)).doubleValue()); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas Phasor is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + // returns the product of the array elements as a String + public String product_as_String(){ + return this.getProduct_as_String(); + } + + public String getProduct_as_String(){ + if(this.suppressMessages)Conv.suppressMessages(); + if(!this.productDone)this.calcProduct(); + String product= " "; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 18: product= Double.toString(((Double)this.productt.get(0)).doubleValue()); + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: if(this.productlongToDouble){ + product= Double.toString(((Double)this.productt.get(0)).doubleValue()); + } + else{ + product= Double.toString(((Long)this.productt.get(0)).doubleValue()); + } + break; + case 12: product= ((BigDecimal)this.productt.get(0)).toString(); + break; + case 13: product= ((BigInteger)this.productt.get(0)).toString(); + break; + case 14: + case 15: throw new IllegalArgumentException("The " + this.typeName[this.type] + " is not a numerical type for which a productas String is meaningful/supported"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + + Conv.restoreMessages(); + return product; + } + + // randomize the order of the elements in the internal array + public ArrayMaths randomize(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + am.type = this.type; + PsRandom ran = new PsRandom(); + am.sortedIndices = ran.uniqueIntegerArray(this.length-1); + + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)am.array.add((Double)this.array.get(am.sortedIndices[i])); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)am.array.add((Float)this.array.get(am.sortedIndices[i])); + break; + case 4: + case 5:for(int i=0; i<this.length; i++)am.array.add((Long)this.array.get(am.sortedIndices[i])); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)am.array.add((Integer)this.array.get(am.sortedIndices[i])); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)am.array.add((Short)this.array.get(am.sortedIndices[i])); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)am.array.add((Byte)this.array.get(am.sortedIndices[i])); + break; + case 12: for(int i=0; i<this.length; i++)am.array.add((BigDecimal)this.array.get(am.sortedIndices[i])); + break; + case 13: for(int i=0; i<this.length; i++)am.array.add((BigInteger)this.array.get(am.sortedIndices[i])); + break; + case 14: for(int i=0; i<this.length; i++)am.array.add((Complex)this.array.get(am.sortedIndices[i])); + break; + case 15: for(int i=0; i<this.length; i++)am.array.add((Phasor)this.array.get(am.sortedIndices[i])); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)am.array.add((Character)this.array.get(am.sortedIndices[i])); + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(am.sortedIndices[i])); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // randomize the order of the elements in the internal array + public ArrayMaths randomise(){ + return this.randomize(); + } + + + // sort the array into ascending order + public ArrayMaths sort(){ + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + am.type = this.type; + am.sortedIndices = new int[this.length]; + + switch(this.type){ + case 0: + case 1: double[] dd1 = this.getArray_as_double(); + am.sortedIndices = this.sortWithIndices(dd1); + for(int i=0; i<this.length; i++)am.array.add((Double)this.array.get(am.sortedIndices[i])); + break; + case 2: + case 3: double[] dd2 = this.getArray_as_double(); + am.sortedIndices = this.sortWithIndices(dd2); + for(int i=0; i<this.length; i++)am.array.add((Float)this.array.get(am.sortedIndices[i])); + break; + case 4: + case 5: long[] ll1 = this.getArray_as_long(); + am.sortedIndices = this.sortWithIndices(ll1); + for(int i=0; i<this.length; i++)am.array.add((Long)this.array.get(am.sortedIndices[i])); + break; + case 6: + case 7: long[] ll2 = this.getArray_as_long(); + am.sortedIndices = this.sortWithIndices(ll2); + for(int i=0; i<this.length; i++)am.array.add((Integer)this.array.get(am.sortedIndices[i])); + break; + case 8: + case 9: long[] ll3 = this.getArray_as_long(); + am.sortedIndices = this.sortWithIndices(ll3); + for(int i=0; i<this.length; i++)am.array.add((Short)this.array.get(am.sortedIndices[i])); + break; + case 10: + case 11: long[] ll4 = this.getArray_as_long(); + am.sortedIndices = this.sortWithIndices(ll4); + for(int i=0; i<this.length; i++)am.array.add((Byte)this.array.get(am.sortedIndices[i])); + break; + case 12: BigDecimal[] bd = this.getArray_as_BigDecimal(); + am.sortedIndices = this.sortWithIndices(bd); + for(int i=0; i<this.length; i++)am.array.add((BigDecimal)this.array.get(am.sortedIndices[i])); + break; + case 13: BigInteger[] bi = this.getArray_as_BigInteger(); + am.sortedIndices = this.sortWithIndices(bi); + for(int i=0; i<this.length; i++)am.array.add((BigInteger)this.array.get(am.sortedIndices[i])); + break; + case 14: ArrayMaths am2 = this.abs(); + double[] cc = am2.getArray_as_double(); + am.sortedIndices = this.sortWithIndices(cc); + for(int i=0; i<this.length; i++)am.array.add((Complex)this.array.get(am.sortedIndices[i])); + break; + case 15: ArrayMaths am3 = this.abs(); + double[] pp = am3.getArray_as_double(); + am.sortedIndices = this.sortWithIndices(pp); + for(int i=0; i<this.length; i++)am.array.add((Phasor)this.array.get(am.sortedIndices[i])); + break; + case 16: + case 17: long[]ii = this.getArray_as_long(); + am.sortedIndices = this.sortWithIndices(ii); + for(int i=0; i<this.length; i++)am.array.add((Character)this.array.get(am.sortedIndices[i])); + break; + case 18: throw new IllegalArgumentException("Alphabetic sorting is not supported by this method"); + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // order an array to a given sequence of indices + public ArrayMaths sort(int[] indices){ + int nArg = indices.length; + if(this.length!=nArg)throw new IllegalArgumentException("The argument array [length = " + nArg + "], must be of the same length as this instance array [length = " + this.length +"]"); + + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = this.length; + am.type = this.type; + am.sortedIndices = indices; + switch(this.type){ + case 0: + case 1: for(int i=0; i<this.length; i++)am.array.add((Double)this.array.get(am.sortedIndices[i])); + break; + case 2: + case 3: for(int i=0; i<this.length; i++)am.array.add((Float)this.array.get(am.sortedIndices[i])); + break; + case 4: + case 5: for(int i=0; i<this.length; i++)am.array.add((Long)this.array.get(am.sortedIndices[i])); + break; + case 6: + case 7: for(int i=0; i<this.length; i++)am.array.add((Integer)this.array.get(am.sortedIndices[i])); + break; + case 8: + case 9: for(int i=0; i<this.length; i++)am.array.add((Short)this.array.get(am.sortedIndices[i])); + break; + case 10: + case 11: for(int i=0; i<this.length; i++)am.array.add((Byte)this.array.get(am.sortedIndices[i])); + break; + case 12: for(int i=0; i<this.length; i++)am.array.add((BigDecimal)this.array.get(am.sortedIndices[i])); + break; + case 13: for(int i=0; i<this.length; i++)am.array.add((BigInteger)this.array.get(am.sortedIndices[i])); + break; + case 14: for(int i=0; i<this.length; i++)am.array.add((Complex)this.array.get(am.sortedIndices[i])); + break; + case 15: for(int i=0; i<this.length; i++)am.array.add((Phasor)this.array.get(am.sortedIndices[i])); + break; + case 16: + case 17: for(int i=0; i<this.length; i++)am.array.add((Character)this.array.get(am.sortedIndices[i])); + break; + case 18: for(int i=0; i<this.length; i++)am.array.add((String)this.array.get(am.sortedIndices[i])); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + if(this.type!=18)ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + + // sort elements in an array into ascending order + // using selection sort method + // returns indices of the sorted array + protected int[] sortWithIndices(double[] aa){ + + int index = 0; + int lastIndex = -1; + double holdb = 0.0D; + int holdi = 0; + double[] bb = new double[this.length]; + int[] indices = new int[this.length]; + for(int i=0; i<this.length; i++){ + bb[i]=aa[i]; + indices[i]=i; + } + + while(lastIndex != this.length-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<this.length; i++){ + if(bb[i]<bb[index]){ + index=i; + } + } + lastIndex++; + holdb=bb[index]; + bb[index]=bb[lastIndex]; + bb[lastIndex]=holdb; + holdi=indices[index]; + indices[index]=indices[lastIndex]; + indices[lastIndex]=holdi; + } + return indices; + } + + // protected method for obtaining original indices of a sorted array + // called by public sort methods + protected int[] sortWithIndices(long[] aa){ + int index = 0; + int lastIndex = -1; + long holdb = 0L; + int holdi = 0; + long[] bb = new long[this.length]; + int[] indices = new int[this.length]; + for(int i=0; i<this.length; i++){ + bb[i]=aa[i]; + indices[i]=i; + } + + while(lastIndex != this.length-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<this.length; i++){ + if(bb[i]<bb[index]){ + index=i; + } + } + lastIndex++; + holdb=bb[index]; + bb[index]=bb[lastIndex]; + bb[lastIndex]=holdb; + holdi=indices[index]; + indices[index]=indices[lastIndex]; + indices[lastIndex]=holdi; + } + return indices; + } + + // protected method for obtaining original indices of a sorted array + // called by public sort methods + protected int[] sortWithIndices(BigDecimal[] aa){ + int index = 0; + int lastIndex = -1; + BigDecimal holdb = BigDecimal.ZERO; + int holdi = 0; + BigDecimal[] bb = new BigDecimal[this.length]; + int[] indices = new int[this.length]; + for(int i=0; i<this.length; i++){ + bb[i]=aa[i]; + indices[i]=i; + } + + while(lastIndex != this.length-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<this.length; i++){ + if(bb[i].compareTo(bb[index])==-1){ + index=i; + } + } + lastIndex++; + holdb=bb[index]; + bb[index]=bb[lastIndex]; + bb[lastIndex]=holdb; + holdi=indices[index]; + indices[index]=indices[lastIndex]; + indices[lastIndex]=holdi; + } + + holdb = null; + return indices; + } + + // protected method for obtaining original indices of a sorted array + // called by public sort methods + protected int[] sortWithIndices(BigInteger[] aa){ + int index = 0; + int lastIndex = -1; + BigInteger holdb = BigInteger.ZERO; + int holdi = 0; + BigInteger[] bb = new BigInteger[this.length]; + int[] indices = new int[this.length]; + for(int i=0; i<this.length; i++){ + bb[i]=aa[i]; + indices[i]=i; + } + + while(lastIndex != this.length-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<this.length; i++){ + if(bb[i].compareTo(bb[index])==-1){ + index=i; + } + } + lastIndex++; + holdb=bb[index]; + bb[index]=bb[lastIndex]; + bb[lastIndex]=holdb; + holdi=indices[index]; + indices[index]=indices[lastIndex]; + indices[lastIndex]=holdi; + } + + holdb = null; + return indices; + } + + + // return original indices of sorted array + public int[] originalIndices(){ + if(this.sortedIndices==null)System.out.println("method: originalIndices: array has not been sorted: null returned"); + return this.sortedIndices; + } + + + // concatenates two arrays + public ArrayMaths concatenate(double[] xx){ + int xlength = xx.length; + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = xx.length + this.length; + ArrayMaths am2 = null; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: double[] yy = this.getArray_as_double(); + double[] zz = new double[am.length]; + for(int i=0; i<this.length; i++)zz[i] = yy[i]; + for(int i=0; i<xlength; i++)zz[i+this.length] = xx[i]; + for(int i=0; i<am.length; i++)am.array.add(new Double(zz[i])); + am.type = 1; + break; + case 12: + case 13: BigDecimal[] bd1 = this.getArray_as_BigDecimal(); + am2 = new ArrayMaths(xx); + BigDecimal[] bd2 = am2.getArray_as_BigDecimal(); + BigDecimal[] bda = new BigDecimal[am.length]; + for(int i=0; i<this.length; i++)bda[i] = bd1[i]; + for(int i=0; i<xlength; i++)bda[i+this.length] = bd2[i]; + for(int i=0; i<am.length; i++)am.array.add(bda[i]); + bd1 = null; + bd2 = null; + bda = null; + am.type = 12; + break; + case 14: Complex[] cc1 = this.getArray_as_Complex(); + am2 = new ArrayMaths(xx); + Complex[] cc2 = am2.getArray_as_Complex(); + Complex[] cca = new Complex[am.length]; + for(int i=0; i<this.length; i++)cca[i] = cc1[i]; + for(int i=0; i<xlength; i++)cca[i+this.length] = cc2[i]; + for(int i=0; i<am.length; i++)am.array.add(cca[i]); + am.type = 14; + break; + case 15: Phasor[] pp1 = this.getArray_as_Phasor(); + am2 = new ArrayMaths(xx); + Phasor[] pp2 = am2.getArray_as_Phasor(); + Phasor[] ppa = new Phasor[am.length]; + for(int i=0; i<this.length; i++)ppa[i] = pp1[i]; + for(int i=0; i<xlength; i++)ppa[i+this.length] = pp2[i]; + for(int i=0; i<am.length; i++)am.array.add(ppa[i]); + am.type = 15; + break; + case 18: String[] ss1 = this.getArray_as_String(); + am2 = new ArrayMaths(xx); + String[] ss2 = am2.getArray_as_String(); + String[] ssa = new String[am.length]; + for(int i=0; i<this.length; i++)ssa[i] = ss1[i]; + for(int i=0; i<xlength; i++)ssa[i+this.length] = ss2[i]; + for(int i=0; i<am.length; i++)am.array.add(ssa[i]); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + public ArrayMaths concatenate(Double[] xx){ + double[] dd = new double[xx.length]; + for(int i=0; i<xx.length; i++)dd[i] = xx[i].doubleValue(); + return this.concatenate(dd); + } + + + // concatenates two arrays + public ArrayMaths concatenate(float[] xx){ + int xlength = xx.length; + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = xx.length + this.length; + ArrayMaths am2 = null; + switch(this.type){ + case 0: + case 1: + case 2: + case 3:double[] yy = this.getArray_as_double(); + double[] zz = new double[am.length]; + for(int i=0; i<this.length; i++)zz[i] = yy[i]; + for(int i=0; i<xlength; i++)zz[i+this.length] = (double)xx[i]; + for(int i=0; i<am.length; i++)am.array.add(new Double(zz[i])); + am.type = 1; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: float[] ff = this.getArray_as_float(); + float[] gg = new float[am.length]; + for(int i=0; i<this.length; i++)gg[i] = ff[i]; + for(int i=0; i<xlength; i++)gg[i+this.length] = xx[i]; + for(int i=0; i<am.length; i++)am.array.add(new Float(gg[i])); + am.type = 3; + break; + case 12: + case 13: BigDecimal[] bd1 = this.getArray_as_BigDecimal(); + am2 = new ArrayMaths(xx); + BigDecimal[] bd2 = am2.getArray_as_BigDecimal(); + BigDecimal[] bda = new BigDecimal[am.length]; + for(int i=0; i<this.length; i++)bda[i] = bd1[i]; + for(int i=0; i<xlength; i++)bda[i+this.length] = bd2[i]; + for(int i=0; i<am.length; i++)am.array.add(bda[i]); + bd1 = null; + bd2 = null; + bda = null; + am.type = 12; + break; + case 14: Complex[] cc1 = this.getArray_as_Complex(); + am2 = new ArrayMaths(xx); + Complex[] cc2 = am2.getArray_as_Complex(); + Complex[] cca = new Complex[am.length]; + for(int i=0; i<this.length; i++)cca[i] = cc1[i]; + for(int i=0; i<xlength; i++)cca[i+this.length] = cc2[i]; + for(int i=0; i<am.length; i++)am.array.add(cca[i]); + am.type = 14; + break; + case 15: Phasor[] pp1 = this.getArray_as_Phasor(); + am2 = new ArrayMaths(xx); + Phasor[] pp2 = am2.getArray_as_Phasor(); + Phasor[] ppa = new Phasor[am.length]; + for(int i=0; i<this.length; i++)ppa[i] = pp1[i]; + for(int i=0; i<xlength; i++)ppa[i+this.length] = pp2[i]; + for(int i=0; i<am.length; i++)am.array.add(ppa[i]); + am.type = 15; + break; + case 18: String[] ss1 = this.getArray_as_String(); + am2 = new ArrayMaths(xx); + String[] ss2 = am2.getArray_as_String(); + String[] ssa = new String[am.length]; + for(int i=0; i<this.length; i++)ssa[i] = ss1[i]; + for(int i=0; i<xlength; i++)ssa[i+this.length] = ss2[i]; + for(int i=0; i<am.length; i++)am.array.add(ssa[i]); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // concatenates two arrays + public ArrayMaths concatenate(Float[] xx){ + float[] dd = new float[xx.length]; + for(int i=0; i<xx.length; i++)dd[i] = xx[i].floatValue(); + return this.concatenate(dd); + } + + // concatenates two arrays + public ArrayMaths concatenate(long[] xx){ + int xlength = xx.length; + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = xx.length + this.length; + ArrayMaths am2 = null; + switch(this.type){ + case 0: + case 1: + case 2: + case 3:double[] yy = this.getArray_as_double(); + double[] zz = new double[am.length]; + for(int i=0; i<this.length; i++)zz[i] = yy[i]; + for(int i=0; i<xlength; i++)zz[i+this.length] = (double)xx[i]; + for(int i=0; i<am.length; i++)am.array.add(new Double(zz[i])); + am.type = 1; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: long[] ll = this.getArray_as_long(); + long[] mm = new long[am.length]; + for(int i=0; i<this.length; i++)mm[i] = ll[i]; + for(int i=0; i<xlength; i++)mm[i+this.length] = xx[i]; + for(int i=0; i<am.length; i++)am.array.add(new Long(mm[i])); + am.type = 3; + break; + case 12: BigDecimal[] bd1 = this.getArray_as_BigDecimal(); + am2 = new ArrayMaths(xx); + BigDecimal[] bd2 = am2.getArray_as_BigDecimal(); + BigDecimal[] bda = new BigDecimal[am.length]; + for(int i=0; i<this.length; i++)bda[i] = bd1[i]; + for(int i=0; i<xlength; i++)bda[i+this.length] = bd2[i]; + for(int i=0; i<am.length; i++)am.array.add(bda[i]); + bd1 = null; + bd2 = null; + bda = null; + am.type = 12; + break; + case 13: BigInteger[] bi1 = this.getArray_as_BigInteger(); + am2 = new ArrayMaths(xx); + BigInteger[] bi2 = am2.getArray_as_BigInteger(); + BigInteger[] bia = new BigInteger[am.length]; + for(int i=0; i<this.length; i++)bia[i] = bi1[i]; + for(int i=0; i<xlength; i++)bia[i+this.length] = bi2[i]; + for(int i=0; i<am.length; i++)am.array.add(bia[i]); + bi1 = null; + bi2 = null; + bia = null; + am.type = 13; + break; + case 14: Complex[] cc1 = this.getArray_as_Complex(); + am2 = new ArrayMaths(xx); + Complex[] cc2 = am2.getArray_as_Complex(); + Complex[] cca = new Complex[am.length]; + for(int i=0; i<this.length; i++)cca[i] = cc1[i]; + for(int i=0; i<xlength; i++)cca[i+this.length] = cc2[i]; + for(int i=0; i<am.length; i++)am.array.add(cca[i]); + am.type = 14; + break; + case 15: Phasor[] pp1 = this.getArray_as_Phasor(); + am2 = new ArrayMaths(xx); + Phasor[] pp2 = am2.getArray_as_Phasor(); + Phasor[] ppa = new Phasor[am.length]; + for(int i=0; i<this.length; i++)ppa[i] = pp1[i]; + for(int i=0; i<xlength; i++)ppa[i+this.length] = pp2[i]; + for(int i=0; i<am.length; i++)am.array.add(ppa[i]); + am.type = 15; + break; + case 18: String[] ss1 = this.getArray_as_String(); + am2 = new ArrayMaths(xx); + String[] ss2 = am2.getArray_as_String(); + String[] ssa = new String[am.length]; + for(int i=0; i<this.length; i++)ssa[i] = ss1[i]; + for(int i=0; i<xlength; i++)ssa[i+this.length] = ss2[i]; + for(int i=0; i<am.length; i++)am.array.add(ssa[i]); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // concatenates two arrays + public ArrayMaths concatenate(Long[] xx){ + long[] dd = new long[xx.length]; + for(int i=0; i<xx.length; i++)dd[i] = xx[i].longValue(); + return this.concatenate(dd); + } + + // concatenates two arrays + public ArrayMaths concatenate(int[] xx){ + long[] dd = new long[xx.length]; + for(int i=0; i<xx.length; i++)dd[i] = (long)xx[i]; + return this.concatenate(dd); + } + + // concatenates two arrays + public ArrayMaths concatenate(Integer[] xx){ + int[] dd = new int[xx.length]; + for(int i=0; i<xx.length; i++)dd[i] = xx[i].intValue(); + return this.concatenate(dd); + } + + // concatenates two arrays + public ArrayMaths concatenate(short[] xx){ + long[] dd = new long[xx.length]; + for(int i=0; i<xx.length; i++)dd[i] = (long)xx[i]; + return this.concatenate(dd); + } + + // concatenates two arrays + public ArrayMaths concatenate(Short[] xx){ + short[] dd = new short[xx.length]; + for(int i=0; i<xx.length; i++)dd[i] = xx[i].shortValue(); + return this.concatenate(dd); + } + + // concatenates two arrays + public ArrayMaths concatenate(byte[] xx){ + long[] dd = new long[xx.length]; + for(int i=0; i<xx.length; i++)dd[i] = (long)xx[i]; + return this.concatenate(dd); + } + + // concatenates two arrays + public ArrayMaths concatenate(Byte[] xx){ + byte[] dd = new byte[xx.length]; + for(int i=0; i<xx.length; i++)dd[i] = xx[i].byteValue(); + return this.concatenate(dd); + } + + // concatenates two arrays + public ArrayMaths concatenate(BigDecimal[] xx){ + int xlength = xx.length; + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = xx.length + this.length; + ArrayMaths am2 = null; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 17: BigDecimal[] bd1 = this.getArray_as_BigDecimal(); + am2 = new ArrayMaths(xx); + BigDecimal[] bd2 = am2.getArray_as_BigDecimal(); + BigDecimal[] bda = new BigDecimal[am.length]; + for(int i=0; i<this.length; i++)bda[i] = bd1[i]; + for(int i=0; i<xlength; i++)bda[i+this.length] = bd2[i]; + for(int i=0; i<am.length; i++)am.array.add(bda[i]); + bd1 = null; + bd2 = null; + bda = null; + am.type = 12; + break; + case 14: Complex[] cc1 = this.getArray_as_Complex(); + am2 = new ArrayMaths(xx); + Complex[] cc2 = am2.getArray_as_Complex(); + Complex[] cca = new Complex[am.length]; + for(int i=0; i<this.length; i++)cca[i] = cc1[i]; + for(int i=0; i<xlength; i++)cca[i+this.length] = cc2[i]; + for(int i=0; i<am.length; i++)am.array.add(cca[i]); + am.type = 14; + break; + case 15: Phasor[] pp1 = this.getArray_as_Phasor(); + am2 = new ArrayMaths(xx); + Phasor[] pp2 = am2.getArray_as_Phasor(); + Phasor[] ppa = new Phasor[am.length]; + for(int i=0; i<this.length; i++)ppa[i] = pp1[i]; + for(int i=0; i<xlength; i++)ppa[i+this.length] = pp2[i]; + for(int i=0; i<am.length; i++)am.array.add(ppa[i]); + am.type = 15; + break; + case 18: String[] ss1 = this.getArray_as_String(); + am2 = new ArrayMaths(xx); + String[] ss2 = am2.getArray_as_String(); + String[] ssa = new String[am.length]; + for(int i=0; i<this.length; i++)ssa[i] = ss1[i]; + for(int i=0; i<xlength; i++)ssa[i+this.length] = ss2[i]; + for(int i=0; i<am.length; i++)am.array.add(ssa[i]); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + public ArrayMaths concatenate(BigInteger[] xx){ + int xlength = xx.length; + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = xx.length + this.length; + ArrayMaths am2 = null; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 12: BigDecimal[] bd1 = this.getArray_as_BigDecimal(); + am2 = new ArrayMaths(xx); + BigDecimal[] bd2 = am2.getArray_as_BigDecimal(); + BigDecimal[] bda = new BigDecimal[am.length]; + for(int i=0; i<this.length; i++)bda[i] = bd1[i]; + for(int i=0; i<xlength; i++)bda[i+this.length] = bd2[i]; + for(int i=0; i<am.length; i++)am.array.add(bda[i]); + bd1 = null; + bd2 = null; + bda = null; + am.type = 12; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 13: + case 16: + case 17: BigInteger[] bi1 = this.getArray_as_BigInteger(); + am2 = new ArrayMaths(xx); + BigInteger[] bi2 = am2.getArray_as_BigInteger(); + BigInteger[] bia = new BigInteger[am.length]; + for(int i=0; i<this.length; i++)bia[i] = bi1[i]; + for(int i=0; i<xlength; i++)bia[i+this.length] = bi2[i]; + for(int i=0; i<am.length; i++)am.array.add(bia[i]); + bi1 = null; + bi2 = null; + bia = null; + am.type = 13; + break; + case 14: Complex[] cc1 = this.getArray_as_Complex(); + am2 = new ArrayMaths(xx); + Complex[] cc2 = am2.getArray_as_Complex(); + Complex[] cca = new Complex[am.length]; + for(int i=0; i<this.length; i++)cca[i] = cc1[i]; + for(int i=0; i<xlength; i++)cca[i+this.length] = cc2[i]; + for(int i=0; i<am.length; i++)am.array.add(cca[i]); + am.type = 14; + break; + case 15: Phasor[] pp1 = this.getArray_as_Phasor(); + am2 = new ArrayMaths(xx); + Phasor[] pp2 = am2.getArray_as_Phasor(); + Phasor[] ppa = new Phasor[am.length]; + for(int i=0; i<this.length; i++)ppa[i] = pp1[i]; + for(int i=0; i<xlength; i++)ppa[i+this.length] = pp2[i]; + for(int i=0; i<am.length; i++)am.array.add(ppa[i]); + am.type = 15; + break; + case 18: String[] ss1 = this.getArray_as_String(); + am2 = new ArrayMaths(xx); + String[] ss2 = am2.getArray_as_String(); + String[] ssa = new String[am.length]; + for(int i=0; i<this.length; i++)ssa[i] = ss1[i]; + for(int i=0; i<xlength; i++)ssa[i+this.length] = ss2[i]; + for(int i=0; i<am.length; i++)am.array.add(ssa[i]); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // concatenates two arrays + public ArrayMaths concatenate(Complex[] xx){ + int xlength = xx.length; + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = xx.length + this.length; + ArrayMaths am2 = null; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: Complex[] cc1 = this.getArray_as_Complex(); + am2 = new ArrayMaths(xx); + Complex[] cc2 = am2.getArray_as_Complex(); + Complex[] cca = new Complex[am.length]; + for(int i=0; i<this.length; i++)cca[i] = cc1[i]; + for(int i=0; i<xlength; i++)cca[i+this.length] = cc2[i]; + for(int i=0; i<am.length; i++)am.array.add(cca[i]); + am.type = 14; + break; + case 18: String[] ss1 = this.getArray_as_String(); + am2 = new ArrayMaths(xx); + String[] ss2 = am2.getArray_as_String(); + String[] ssa = new String[am.length]; + for(int i=0; i<this.length; i++)ssa[i] = ss1[i]; + for(int i=0; i<xlength; i++)ssa[i+this.length] = ss2[i]; + for(int i=0; i<am.length; i++)am.array.add(ssa[i]); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + // concatenates two arrays + public ArrayMaths concatenate(Phasor[] xx){ + int xlength = xx.length; + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = xx.length + this.length; + ArrayMaths am2 = null; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: Phasor[] pp1 = this.getArray_as_Phasor(); + am2 = new ArrayMaths(xx); + Phasor[] pp2 = am2.getArray_as_Phasor(); + Phasor[] ppa = new Phasor[am.length]; + for(int i=0; i<this.length; i++)ppa[i] = pp1[i]; + for(int i=0; i<xlength; i++)ppa[i+this.length] = pp2[i]; + for(int i=0; i<am.length; i++)am.array.add(ppa[i]); + am.type = 15; + break; + case 18: String[] ss1 = this.getArray_as_String(); + am2 = new ArrayMaths(xx); + String[] ss2 = am2.getArray_as_String(); + String[] ssa = new String[am.length]; + for(int i=0; i<this.length; i++)ssa[i] = ss1[i]; + for(int i=0; i<xlength; i++)ssa[i+this.length] = ss2[i]; + for(int i=0; i<am.length; i++)am.array.add(ssa[i]); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + // concatenates two arrays + public ArrayMaths concatenate(String[] xx){ + int xlength = xx.length; + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = xx.length + this.length; + ArrayMaths am2 = null; + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: String[] ss1 = this.getArray_as_String(); + am2 = new ArrayMaths(xx); + String[] ss2 = am2.getArray_as_String(); + String[] ssa = new String[am.length]; + for(int i=0; i<this.length; i++)ssa[i] = ss1[i]; + for(int i=0; i<xlength; i++)ssa[i+this.length] = ss2[i]; + for(int i=0; i<am.length; i++)am.array.add(ssa[i]); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + Conv.restoreMessages(); + return am; + } + + // concatenates two arrays + public ArrayMaths concatenate(char[] xx){ + int xlength = xx.length; + if(this.suppressMessages)Conv.suppressMessages(); + ArrayMaths am = new ArrayMaths(); + am.array = new ArrayList<Object>(); + am.length = xx.length + this.length; + ArrayMaths am2 = null; + switch(this.type){ + case 0: + case 1: + case 2: + case 3:double[] yy = this.getArray_as_double(); + double[] zz = new double[am.length]; + for(int i=0; i<this.length; i++)zz[i] = yy[i]; + for(int i=0; i<xlength; i++)zz[i+this.length] = (double)xx[i]; + for(int i=0; i<am.length; i++)am.array.add(new Double(zz[i])); + am.type = 1; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: long[] ll = this.getArray_as_long(); + long[] mm = new long[am.length]; + for(int i=0; i<this.length; i++)mm[i] = ll[i]; + for(int i=0; i<xlength; i++)mm[i+this.length] = xx[i]; + for(int i=0; i<am.length; i++)am.array.add(new Long(mm[i])); + am.type = 3; + break; + case 12: BigDecimal[] bd1 = this.getArray_as_BigDecimal(); + am2 = new ArrayMaths(xx); + BigDecimal[] bd2 = am2.getArray_as_BigDecimal(); + BigDecimal[] bda = new BigDecimal[am.length]; + for(int i=0; i<this.length; i++)bda[i] = bd1[i]; + for(int i=0; i<xlength; i++)bda[i+this.length] = bd2[i]; + for(int i=0; i<am.length; i++)am.array.add(bda[i]); + bd1 = null; + bd2 = null; + bda = null; + am.type = 12; + break; + case 13: BigInteger[] bi1 = this.getArray_as_BigInteger(); + am2 = new ArrayMaths(xx); + BigInteger[] bi2 = am2.getArray_as_BigInteger(); + BigInteger[] bia = new BigInteger[am.length]; + for(int i=0; i<this.length; i++)bia[i] = bi1[i]; + for(int i=0; i<xlength; i++)bia[i+this.length] = bi2[i]; + for(int i=0; i<am.length; i++)am.array.add(bia[i]); + bi1 = null; + bi2 = null; + bia = null; + am.type = 13; + break; + case 14: Complex[] cc1 = this.getArray_as_Complex(); + am2 = new ArrayMaths(xx); + Complex[] cc2 = am2.getArray_as_Complex(); + Complex[] cca = new Complex[am.length]; + for(int i=0; i<this.length; i++)cca[i] = cc1[i]; + for(int i=0; i<xlength; i++)cca[i+this.length] = cc2[i]; + for(int i=0; i<am.length; i++)am.array.add(cca[i]); + am.type = 14; + break; + case 15: Phasor[] pp1 = this.getArray_as_Phasor(); + am2 = new ArrayMaths(xx); + Phasor[] pp2 = am2.getArray_as_Phasor(); + Phasor[] ppa = new Phasor[am.length]; + for(int i=0; i<this.length; i++)ppa[i] = pp1[i]; + for(int i=0; i<xlength; i++)ppa[i+this.length] = pp2[i]; + for(int i=0; i<am.length; i++)am.array.add(ppa[i]); + am.type = 15; + break; + case 16: + case 17: char[] ch = this.getArray_as_char(); + char[] dh = new char[am.length]; + for(int i=0; i<this.length; i++)dh[i] = ch[i]; + for(int i=0; i<xlength; i++)dh[i+this.length] = xx[i]; + for(int i=0; i<am.length; i++)am.array.add(new Character(dh[i])); + am.type = 1; + break; + case 18: String[] ss1 = this.getArray_as_String(); + am2 = new ArrayMaths(xx); + String[] ss2 = am2.getArray_as_String(); + String[] ssa = new String[am.length]; + for(int i=0; i<this.length; i++)ssa[i] = ss1[i]; + for(int i=0; i<xlength; i++)ssa[i+this.length] = ss2[i]; + for(int i=0; i<am.length; i++)am.array.add(ssa[i]); + am.type = 18; + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // concatenates two arrays + public ArrayMaths concatenate(Character[] xx){ + char[] dd = new char[xx.length]; + for(int i=0; i<xx.length; i++)dd[i] = xx[i].charValue(); + return this.concatenate(dd); + } + + // concatenates two arrays + public ArrayMaths concatenate(ArrayMaths xx){ + if(this.suppressMessages)Conv.suppressMessages(); + int type = xx.type; + ArrayMaths am = new ArrayMaths(); + switch(xx.type){ + case 0: + case 1: double[] dd = xx.getArray_as_double(); + am = this.concatenate(dd); + break; + case 2: + case 3: float[] ff = xx.getArray_as_float(); + am = this.concatenate(ff); + break; + case 4: + case 5: long[] ll = xx.getArray_as_long(); + am = this.concatenate(ll); + break; + case 6: + case 7: int[] ii = xx.getArray_as_int(); + am = this.concatenate(ii); + break; + case 8: + case 9: short[] ss = xx.getArray_as_short(); + am = this.concatenate(ss); + break; + case 10: + case 11: byte[] bb = xx.getArray_as_byte(); + am = this.concatenate(bb); + break; + case 12: BigDecimal[] bd = xx.getArray_as_BigDecimal(); + am = this.concatenate(bd); + break; + case 13: BigInteger[] bi = this.getArray_as_BigInteger(); + am = this.concatenate(bi); + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + am = this.concatenate(cc); + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + am = this.concatenate(pp); + break; + case 16: + case 17: char[] ct = this.getArray_as_char(); + am = this.concatenate(ct); + break; + case 18: String[] st = this.getArray_as_String(); + am = this.concatenate(st); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + // concatenates two arrays + public ArrayMaths concatenate(Stat xx){ + if(this.suppressMessages)Conv.suppressMessages(); + int type = xx.type; + ArrayMaths am = new ArrayMaths(); + switch(xx.type){ + case 0: + case 1: double[] dd = xx.getArray_as_double(); + am = this.concatenate(dd); + break; + case 2: + case 3: float[] ff = xx.getArray_as_float(); + am = this.concatenate(ff); + break; + case 4: + case 5: long[] ll = xx.getArray_as_long(); + am = this.concatenate(ll); + break; + case 6: + case 7: int[] ii = xx.getArray_as_int(); + am = this.concatenate(ii); + break; + case 8: + case 9: short[] ss = xx.getArray_as_short(); + am = this.concatenate(ss); + break; + case 10: + case 11: byte[] bb = xx.getArray_as_byte(); + am = this.concatenate(bb); + break; + case 12: BigDecimal[] bd = xx.getArray_as_BigDecimal(); + am = this.concatenate(bd); + break; + case 13: BigInteger[] bi = this.getArray_as_BigInteger(); + am = this.concatenate(bi); + break; + case 14: Complex[] cc = this.getArray_as_Complex(); + am = this.concatenate(cc); + break; + case 15: Phasor[] pp = this.getArray_as_Phasor(); + am = this.concatenate(pp); + break; + case 16: + case 17: char[] ct = this.getArray_as_char(); + am = this.concatenate(ct); + break; + case 18: String[] st = this.getArray_as_String(); + am = this.concatenate(st); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + int[] maxminIndices = new int[2]; + ArrayMaths.findMinMax(am.getArray_as_Object(), am.minmax, maxminIndices, am.typeName, am.type); + am.maxIndex = maxminIndices[0]; + am.minIndex = maxminIndices[1]; + + Conv.restoreMessages(); + return am; + } + + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(double value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = -1; + if(this.type==0 || this.type==1){ + double[] arrayc = this.getArray_as_double(); + boolean test = true; + int counter = 0; + while(test){ + if(arrayc[counter]==value){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=arrayc.length)test = false; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare double or Double with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(Double value){ + double val = value.doubleValue(); + return this.indexOf(val); + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(float value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = -1; + if(this.type==2 || this.type==3){ + float[] arrayc = this.getArray_as_float(); + boolean test = true; + int counter = 0; + while(test){ + if(arrayc[counter]==value){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=arrayc.length)test = false; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare float or Float with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(Float value){ + float val = value.floatValue(); + return this.indexOf(val); + } + + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(long value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = -1; + if(this.type==4 || this.type==5){ + long[] arrayc = this.getArray_as_long(); + boolean test = true; + int counter = 0; + while(test){ + if(arrayc[counter]==value){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=arrayc.length)test = false; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare long or Long with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(Long value){ + long val = value.longValue(); + return this.indexOf(val); + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(int value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = -1; + if(this.type==6 || this.type==7){ + int[] arrayc = this.getArray_as_int(); + boolean test = true; + int counter = 0; + while(test){ + if(arrayc[counter]==value){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=arrayc.length)test = false; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare int or Integer with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(Integer value){ + int val = value.intValue(); + return this.indexOf(val); + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(short value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = -1; + if(this.type==8 || this.type==9){ + short[] arrayc = this.getArray_as_short(); + boolean test = true; + int counter = 0; + while(test){ + if(arrayc[counter]==value){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=arrayc.length)test = false; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare short or Short with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(Short value){ + short val = value.shortValue(); + return this.indexOf(val); + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(byte value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = -1; + if(this.type==10 || this.type==11){ + byte[] arrayc = this.getArray_as_byte(); + boolean test = true; + int counter = 0; + while(test){ + if(arrayc[counter]==value){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=arrayc.length)test = false; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare byte or Byte with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(Byte value){ + byte val = value.byteValue(); + return this.indexOf(val); + } + + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(char value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = -1; + if(this.type==16 || this.type==17){ + char[] arrayc = this.getArray_as_char(); + boolean test = true; + int counter = 0; + while(test){ + if(arrayc[counter]==value){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=arrayc.length)test = false; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare char or Character with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(Character value){ + char val = value.charValue(); + return this.indexOf(val); + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(String value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = -1; + if(this.type==18){ + String[] arrayc = this.getArray_as_String(); + boolean test = true; + int counter = 0; + while(test){ + if(arrayc[counter].equals(value)){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=arrayc.length)test = false; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare String with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(Complex value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = -1; + if(this.type==14){ + Complex[] arrayc = this.getArray_as_Complex(); + boolean test = true; + int counter = 0; + while(test){ + if(arrayc[counter].equals(value)){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=arrayc.length)test = false; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare Complex with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(Phasor value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = -1; + if(this.type==15){ + Phasor[] arrayc = this.getArray_as_Phasor(); + boolean test = true; + int counter = 0; + while(test){ + if(arrayc[counter].equals(value)){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=arrayc.length)test = false; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare Phasor with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(BigDecimal value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = -1; + if(this.type==12){ + BigDecimal[] arrayc = this.getArray_as_BigDecimal(); + boolean test = true; + int counter = 0; + while(test){ + if(arrayc[counter].compareTo(value)==0){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=arrayc.length)test = false; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare BigDecimal with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array + // returns -1 if none found + public int indexOf(BigInteger value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = -1; + if(this.type==13){ + BigInteger[] arrayc = this.getArray_as_BigInteger(); + boolean test = true; + int counter = 0; + while(test){ + if(arrayc[counter].compareTo(value)==0){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=arrayc.length)test = false; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare BigInteger with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(double value){ + if(this.suppressMessages)Conv.suppressMessages(); + int[] indices = null; + int numberOfIndices = 0; + if(this.type==0 || this.type==1){ + double[] arrayc = this.getArray_as_double(); + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<this.length; i++){ + if(arrayc[i]==value){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare double or Double with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return indices; + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(Double value){ + double val = value.doubleValue(); + return this.indicesOf(val); + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(float value){ + if(this.suppressMessages)Conv.suppressMessages(); + int[] indices = null; + int numberOfIndices = 0; + if(this.type==2 || this.type==3){ + float[] arrayc = this.getArray_as_float(); + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<this.length; i++){ + if(arrayc[i]==value){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare float or Float with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return indices; + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(Float value){ + float val = value.floatValue(); + return this.indicesOf(val); + } + + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(long value){ + if(this.suppressMessages)Conv.suppressMessages(); + int[] indices = null; + int numberOfIndices = 0; + if(this.type==4 || this.type==5){ + long[] arrayc = this.getArray_as_long(); + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<this.length; i++){ + if(arrayc[i]==value){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare long or Long with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return indices; + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(Long value){ + long val = value.longValue(); + return this.indicesOf(val); + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(int value){ + if(this.suppressMessages)Conv.suppressMessages(); + int[] indices = null; + int numberOfIndices = 0; + if(this.type==6 || this.type==7){ + int[] arrayc = this.getArray_as_int(); + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<this.length; i++){ + if(arrayc[i]==value){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare int or Integer with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return indices; + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(Integer value){ + int val = value.intValue(); + return this.indicesOf(val); + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(short value){ + if(this.suppressMessages)Conv.suppressMessages(); + int[] indices = null; + int numberOfIndices = 0; + if(this.type==8 || this.type==9){ + short[] arrayc = this.getArray_as_short(); + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<this.length; i++){ + if(arrayc[i]==value){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare short or Short with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return indices; + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(Short value){ + short val = value.shortValue(); + return this.indicesOf(val); + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(byte value){ + if(this.suppressMessages)Conv.suppressMessages(); + int[] indices = null; + int numberOfIndices = 0; + if(this.type==10 || this.type==11){ + byte[] arrayc = this.getArray_as_byte(); + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<this.length; i++){ + if(arrayc[i]==value){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare byte or Byte with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return indices; + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(Byte value){ + byte val = value.byteValue(); + return this.indicesOf(val); + } + + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(char value){ + if(this.suppressMessages)Conv.suppressMessages(); + int[] indices = null; + int numberOfIndices = 0; + if(this.type==16 || this.type==17){ + char[] arrayc = this.getArray_as_char(); + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<this.length; i++){ + if(arrayc[i]==value){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare char or Character with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return indices; + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(Character value){ + char val = value.charValue(); + return this.indicesOf(val); + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(String value){ + if(this.suppressMessages)Conv.suppressMessages(); + int[] indices = null; + int numberOfIndices = 0; + if(this.type==18){ + String[] arrayc = this.getArray_as_String(); + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<this.length; i++){ + if(arrayc[i].equals(value)){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare String with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return indices; + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(Complex value){ + if(this.suppressMessages)Conv.suppressMessages(); + int[] indices = null; + int numberOfIndices = 0; + if(this.type==14){ + Complex[] arrayc = this.getArray_as_Complex(); + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<this.length; i++){ + if(arrayc[i].equals(value)){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare Complex with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return indices; + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(Phasor value){ + if(this.suppressMessages)Conv.suppressMessages(); + int[] indices = null; + int numberOfIndices = 0; + if(this.type==15){ + Phasor[] arrayc = this.getArray_as_Phasor(); + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<this.length; i++){ + if(arrayc[i].equals(value)){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare Phasor with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return indices; + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(BigDecimal value){ + if(this.suppressMessages)Conv.suppressMessages(); + int[] indices = null; + int numberOfIndices = 0; + if(this.type==12){ + BigDecimal[] arrayc = this.getArray_as_BigDecimal(); + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<this.length; i++){ + if(arrayc[i].compareTo(value)==0){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare BigDecimal with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return indices; + } + + // finds all indices of the occurences of the element equal to a given value in an array + // returns null if none found + public int[] indicesOf(BigInteger value){ + if(this.suppressMessages)Conv.suppressMessages(); + int[] indices = null; + int numberOfIndices = 0; + if(this.type==13){ + BigInteger[] arrayc = this.getArray_as_BigInteger(); + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<this.length; i++){ + if(arrayc[i].compareTo(value)==0){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare BigInteger with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return indices; + } + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(double value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = 0; + if(this.type==0 || this.type==1){ + double[] arrayc = this.getArray_as_double(); + double diff = Math.abs(arrayc[0] - value); + double nearest = arrayc[0]; + for(int i=1; i<arrayc.length; i++){ + if(Math.abs(arrayc[i] - value)<diff){ + diff = Math.abs(arrayc[i] - value); + index = i; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare double or Double with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(Double value){ + double val = value.doubleValue(); + return this.nearestIndex(val); + } + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(float value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = 0; + if(this.type==2 || this.type==3){ + float[] arrayc = this.getArray_as_float(); + float diff = Math.abs(arrayc[0] - value); + float nearest = arrayc[0]; + for(int i=1; i<arrayc.length; i++){ + if(Math.abs(arrayc[i] - value)<diff){ + diff = Math.abs(arrayc[i] - value); + index = i; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare float or Float with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(Float value){ + float val = value.floatValue(); + return this.nearestIndex(val); + } + + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(long value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = 0; + if(this.type==4 || this.type==5){ + long[] arrayc = this.getArray_as_long(); + long diff = Math.abs(arrayc[0] - value); + long nearest = arrayc[0]; + for(int i=1; i<arrayc.length; i++){ + if(Math.abs(arrayc[i] - value)<diff){ + diff = Math.abs(arrayc[i] - value); + index = i; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare long or Long with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(Long value){ + long val = value.longValue(); + return this.nearestIndex(val); + } + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(int value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = 0; + if(this.type==6 || this.type==7){ + int[] arrayc = this.getArray_as_int(); + int diff = Math.abs(arrayc[0] - value); + int nearest = arrayc[0]; + for(int i=1; i<arrayc.length; i++){ + if(Math.abs(arrayc[i] - value)<diff){ + diff = Math.abs(arrayc[i] - value); + index = i; + } + } + + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare int or Integer with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(Integer value){ + int val = value.intValue(); + return this.nearestIndex(val); + } + + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(short value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = 0; + if(this.type==8 || this.type==9){ + short[] arrayc = this.getArray_as_short(); + short diff = (short)Math.abs(arrayc[0] - value); + short nearest = arrayc[0]; + for(int i=1; i<arrayc.length; i++){ + if(Math.abs(arrayc[i] - value)<diff){ + diff = (short)Math.abs(arrayc[i] - value); + index = i; + } + } + + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare short or Short with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(Short value){ + short val = value.shortValue(); + return this.nearestIndex(val); + } + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(byte value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = 0; + if(this.type==10 || this.type==11){ + byte[] arrayc = this.getArray_as_byte(); + byte diff = (byte)Math.abs(arrayc[0] - value); + byte nearest = arrayc[0]; + for(int i=1; i<arrayc.length; i++){ + if(Math.abs(arrayc[i] - value)<diff){ + diff = (byte)Math.abs(arrayc[i] - value); + index = i; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare byte or Byte with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(Byte value){ + byte val = value.byteValue(); + return this.nearestIndex(val); + } + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(char value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = 0; + if(this.type==16 || this.type==17){ + int[] arrayc = this.getArray_as_int(); + int diff = Math.abs(arrayc[0] - value); + int nearest = arrayc[0]; + for(int i=1; i<arrayc.length; i++){ + if(Math.abs(arrayc[i] - value)<diff){ + diff = Math.abs(arrayc[i] - value); + index = i; + } + } + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare char or Character with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(Character value){ + char val = value.charValue(); + return this.nearestIndex(val); + } + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(BigDecimal value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = 0; + if(this.type==12){ + BigDecimal[] arrayc = this.getArray_as_BigDecimal(); + BigDecimal diff = (arrayc[0].subtract(value)).abs(); + BigDecimal nearest = arrayc[0]; + for(int i=1; i<arrayc.length; i++){ + if(((arrayc[i].subtract(value)).abs( )).compareTo(diff)==-1){ + diff = (arrayc[i].subtract(value)).abs(); + index = i; + } + } + arrayc = null; + diff = null; + nearest = null; + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare BigDecimal with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the index of the first occurence of the nearest element to a given value in an array + public int nearestIndex(BigInteger value){ + if(this.suppressMessages)Conv.suppressMessages(); + int index = 0; + if(this.type==12){ + BigInteger[] arrayc = this.getArray_as_BigInteger(); + BigInteger diff = (arrayc[0].subtract(value)).abs(); + BigInteger nearest = arrayc[0]; + for(int i=1; i<arrayc.length; i++){ + if(((arrayc[i].subtract(value)).abs( )).compareTo(diff)==-1){ + diff = (arrayc[i].subtract(value)).abs(); + index = i; + } + } + arrayc = null; + diff = null; + nearest = null; + } + else{ + throw new IllegalArgumentException("Only comparisons between the same data types are supported - you are attempting to compare BigInteger with " + this.typeName[this.type]); + } + Conv.restoreMessages(); + return index; + } + + // finds the value of the nearest element to a given value in an array + public double nearestValue(double value){ + int index = this.nearestIndex(value); + double ret = ((Double)(this.array.get(index))).doubleValue(); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public Double nearestValue(Double value){ + int index = this.nearestIndex(value); + Double ret = (Double)(this.array.get(index)); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public float nearestValue(float value){ + int index = this.nearestIndex(value); + float ret = ((Float)(this.array.get(index))).floatValue(); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public Float nearestValue(Float value){ + int index = this.nearestIndex(value); + Float ret = (Float)(this.array.get(index)); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public long nearestValue(long value){ + int index = this.nearestIndex(value); + long ret = ((Long)(this.array.get(index))).longValue(); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public Long nearestValue(Long value){ + int index = this.nearestIndex(value); + Long ret = (Long)(this.array.get(index)); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public int nearestValue(int value){ + int index = this.nearestIndex(value); + int ret = ((Integer)(this.array.get(index))).intValue(); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public Integer nearestValue(Integer value){ + int index = this.nearestIndex(value); + Integer ret = (Integer)(this.array.get(index)); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public short nearestValue(short value){ + int index = this.nearestIndex(value); + short ret = ((Short)(this.array.get(index))).shortValue(); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public Short nearestValue(Short value){ + int index = this.nearestIndex(value); + Short ret = (Short)(this.array.get(index)); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public byte nearestValue(byte value){ + int index = this.nearestIndex(value); + byte ret = ((Byte)(this.array.get(index))).byteValue(); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public Byte nearestValue(Byte value){ + int index = this.nearestIndex(value); + Byte ret = (Byte)(this.array.get(index)); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public char nearestValue(char value){ + int index = this.nearestIndex(value); + char ret = ((Character)(this.array.get(index))).charValue(); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public Character nearestValue(Character value){ + int index = this.nearestIndex(value); + Character ret = (Character)(this.array.get(index)); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public BigDecimal nearestValue(BigDecimal value){ + int index = this.nearestIndex(value); + BigDecimal ret = (BigDecimal)this.array.get(index); + return ret; + } + + // finds the value of the nearest element to a given value in an array + public BigInteger nearestValue(BigInteger value){ + int index = this.nearestIndex(value); + BigInteger ret = (BigInteger)this.array.get(index); + return ret; + } + + // return maximum difference, i.e. range + public double maximumDifference(){ + return this.getMaximumDifference_as_double(); + } + + public double maximumDifference_as_double(){ + return this.getMaximumDifference_as_double(); + } + + public double getMaximumDifference(){ + return this.getMaximumDifference_as_double(); + } + + public double getMaximumDifference_as_double(){ + double diff = 0.0D; + if(this.type==0 || this.type==1){ + double max = this.getMaximum_as_double(); + double min = this.getMinimum_as_double(); + diff = max - min; + } + else{ + throw new IllegalArgumentException("Maximum difference may only be returned as the same type as the type of the internal array - you are trying to return as double or Double the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return maximum difference, i.e. range + public Double maximumDifference_as_Double(){ + return this.getMaximumDifference_as_Double(); + } + + public Double getMaximumDifference_as_Double(){ + return new Double(this.getMaximumDifference_as_double()); + } + + // return maximum difference, i.e. range + public float maximumDifference_as_float(){ + return this.getMaximumDifference_as_float(); + } + + public float getMaximumDifference_as_float(){ + float diff = 0.0F; + if(this.type==2 || this.type==3){ + float max = this.getMaximum_as_float(); + float min = this.getMinimum_as_float(); + diff = max - min; + } + else{ + throw new IllegalArgumentException("Maximum difference may only be returned as the same type as the type of the internal array - you are trying to return as float or Float the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return maximum difference, i.e. range + public Float maximumDifference_as_Float(){ + return this.getMaximumDifference_as_Float(); + } + + public Float getMaximumDifference_as_Float(){ + return new Float(this.getMaximumDifference_as_float()); + } + + // return maximum difference, i.e. range + public long maximumDifference_as_long(){ + return this.getMaximumDifference_as_long(); + } + + public long getMaximumDifference_as_long(){ + long diff = 0L; + if(this.type==4 || this.type==5){ + long max = this.getMaximum_as_long(); + long min = this.getMinimum_as_long(); + diff = max - min; + } + else{ + throw new IllegalArgumentException("Maximum difference may only be returned as the same type as the type of the internal array - you are trying to return as long or Long the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return maximum difference, i.e. range + public Long maximumDifference_as_Long(){ + return this.getMaximumDifference_as_Long(); + } + + public Long getMaximumDifference_as_Long(){ + return new Long(this.getMaximumDifference_as_long()); + } + + // return maximum difference, i.e. range + public int maximumDifference_as_int(){ + return this.getMaximumDifference_as_int(); + } + + public int getMaximumDifference_as_int(){ + int diff = 0; + if(this.type==6 || this.type==7){ + int max = this.getMaximum_as_int(); + int min = this.getMinimum_as_int(); + diff = max - min; + } + else{ + throw new IllegalArgumentException("Maximum difference may only be returned as the same type as the type of the internal array - you are trying to return as int or Integer the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return maximum difference, i.e. range + public Integer maximumDifference_as_Integer(){ + return this.getMaximumDifference_as_Integer(); + } + + public Integer getMaximumDifference_as_Integer(){ + return new Integer(this.getMaximumDifference_as_int()); + } + + // return maximum difference, i.e. range + public short maximumDifference_as_short(){ + return this.getMaximumDifference_as_short(); + } + + public short getMaximumDifference_as_short(){ + short diff = (short) 0; + if(this.type==8 || this.type==9){ + short max = this.getMaximum_as_short(); + short min = this.getMinimum_as_short(); + diff = (short)(max - min); + } + else{ + throw new IllegalArgumentException("Maximum difference may only be returned as the same type as the type of the internal array - you are trying to return as short or Short the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return maximum difference, i.e. range + public Short maximumDifference_as_Short(){ + return this.getMaximumDifference_as_Short(); + } + + public Short getMaximumDifference_as_Short(){ + return new Short(this.getMaximumDifference_as_short()); + } + + // return maximum difference, i.e. range + public byte maximumDifference_as_byte(){ + return this.getMaximumDifference_as_byte(); + } + + public byte getMaximumDifference_as_byte(){ + byte diff = (byte) 0; + if(this.type==10 || this.type==11){ + byte max = this.getMaximum_as_byte(); + byte min = this.getMinimum_as_byte(); + diff = (byte)(max - min); + } + else{ + throw new IllegalArgumentException("Maximum difference may only be returned as the same type as the type of the internal array - you are trying to return as byte or Byte the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return maximum difference, i.e. range + public Byte maximumDifference_as_Byte(){ + return this.getMaximumDifference_as_Byte(); + } + + public Byte getMaximumDifference_as_Byte(){ + return new Byte(this.getMaximumDifference_as_byte()); + } + + // return maximum difference, i.e. range + public BigDecimal maximumDifference_as_BigDecimal(){ + return this.getMaximumDifference_as_BigDecimal(); + } + + public BigDecimal getMaximumDifference_as_BigDecimal(){ + BigDecimal diff = BigDecimal.ZERO; + if(this.type==12){ + BigDecimal max = this.getMaximum_as_BigDecimal(); + BigDecimal min = this.getMinimum_as_BigDecimal(); + diff = max.subtract(min); + max = null; + min = null; + } + else{ + throw new IllegalArgumentException("Maximum difference may only be returned as the same type as the type of the internal array - you are trying to return as BigDecimal the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return maximum difference, i.e. range + public BigInteger maximumDifference_as_BigInteger(){ + return this.getMaximumDifference_as_BigInteger(); + } + + public BigInteger getMaximumDifference_as_BigInteger(){ + BigInteger diff = BigInteger.ZERO; + if(this.type==13){ + BigInteger max = this.getMaximum_as_BigInteger(); + BigInteger min = this.getMinimum_as_BigInteger(); + diff = max.subtract(min); + max = null; + min = null; + } + else{ + throw new IllegalArgumentException("Maximum difference may only be returned as the same type as the type of the internal array - you are trying to return as BigInteger the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return minimum difference + public double minimumDifference(){ + return this.getMinimumDifference_as_double(); + } + + public double minimumDifference_as_double(){ + return this.getMinimumDifference_as_double(); + } + + public double getMinimumDifference(){ + return this.getMinimumDifference_as_double(); + } + + public double getMinimumDifference_as_double(){ + double diff = 0.0D; + if(this.type==0 || this.type==1){ + ArrayMaths am = this.sort(); + double[] sorted = am.getArray_as_double(); + diff = sorted[1] - sorted[0]; + double minDiff = diff; + for(int i=1; i<this.length-1; i++){ + diff = sorted[i+1] - sorted[i]; + if(diff<minDiff)minDiff = diff; + } + } + else{ + throw new IllegalArgumentException("Minimum difference may only be returned as the same type as the type of the internal array - you are trying to return as double or Double the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return minimum difference + public Double minimumDifference_as_Double(){ + return this.getMinimumDifference_as_Double(); + } + + public Double getMinimumDifference_as_Double(){ + return new Double(this.getMinimumDifference_as_double()); + } + + // return minimum difference + public float minimumDifference_as_float(){ + return this.getMinimumDifference_as_float(); + } + + public float getMinimumDifference_as_float(){ + float diff = 0.0F; + if(this.type==2 || this.type==3){ + ArrayMaths am = this.sort(); + float[] sorted = am.getArray_as_float(); + diff = sorted[1] - sorted[0]; + float minDiff = diff; + for(int i=1; i<this.length-1; i++){ + diff = sorted[i+1] - sorted[i]; + if(diff<minDiff)minDiff = diff; + } + } + else{ + throw new IllegalArgumentException("Minimum difference may only be returned as the same type as the type of the internal array - you are trying to return as float or Float the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return minimum difference + public Float minimumDifference_as_Float(){ + return this.getMinimumDifference_as_Float(); + } + + public Float getMinimumDifference_as_Float(){ + return new Float(this.getMinimumDifference_as_float()); + } + + // return minimum difference + public long minimumDifference_as_long(){ + return this.getMinimumDifference_as_long(); + } + + public long getMinimumDifference_as_long(){ + long diff = 0L; + if(this.type==4 || this.type==5){ + ArrayMaths am = this.sort(); + long[] sorted = am.getArray_as_long(); + diff = sorted[1] - sorted[0]; + long minDiff = diff; + for(int i=1; i<this.length-1; i++){ + diff = sorted[i+1] - sorted[i]; + if(diff<minDiff)minDiff = diff; + } + } + else{ + throw new IllegalArgumentException("Minimum difference may only be returned as the same type as the type of the internal array - you are trying to return as long or Long the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return minimum difference + public Long minimumDifference_as_Long(){ + return this.getMinimumDifference_as_Long(); + } + + public Long getMinimumDifference_as_Long(){ + return new Long(this.getMinimumDifference_as_long()); + } + + // return minimum difference + public int minimumDifference_as_int(){ + return this.getMinimumDifference_as_int(); + } + + public int getMinimumDifference_as_int(){ + int diff = 0; + if(this.type==6 || this.type==7){ + ArrayMaths am = this.sort(); + int[] sorted = am.getArray_as_int(); + diff = sorted[1] - sorted[0]; + int minDiff = diff; + for(int i=1; i<this.length-1; i++){ + diff = sorted[i+1] - sorted[i]; + if(diff<minDiff)minDiff = diff; + } + } + else{ + throw new IllegalArgumentException("Minimum difference may only be returned as the same type as the type of the internal array - you are trying to return as int or Integer the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return minimum difference + public Integer minimumDifference_as_Integer(){ + return this.getMinimumDifference_as_Integer(); + } + + public Integer getMinimumDifference_as_Integer(){ + return new Integer(this.getMinimumDifference_as_int()); + } + + // return minimum difference + public short minimumDifference_as_short(){ + return this.getMinimumDifference_as_short(); + } + + public short getMinimumDifference_as_short(){ + short diff = (short)0; + if(this.type==8 || this.type==9){ + ArrayMaths am = this.sort(); + short[] sorted = am.getArray_as_short(); + diff = (short)(sorted[1] - sorted[0]); + short minDiff = diff; + for(int i=1; i<this.length-1; i++){ + diff = (short)(sorted[i+1] - sorted[i]); + if(diff<minDiff)minDiff = diff; + } + } + else{ + throw new IllegalArgumentException("Minimum difference may only be returned as the same type as the type of the internal array - you are trying to return as short or Short the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return minimum difference + public Short minimumDifference_as_Short(){ + return this.getMinimumDifference_as_Short(); + } + + public Short getMinimumDifference_as_Short(){ + return new Short(this.getMinimumDifference_as_short()); + } + + + // return minimum difference + public byte minimumDifference_as_byte(){ + return this.getMinimumDifference_as_byte(); + } + + public byte getMinimumDifference_as_byte(){ + byte diff = (byte)0; + if(this.type==10 || this.type==11){ + ArrayMaths am = this.sort(); + byte[] sorted = am.getArray_as_byte(); + diff = (byte)(sorted[1] - sorted[0]); + byte minDiff = diff; + for(int i=1; i<this.length-1; i++){ + diff = (byte)(sorted[i+1] - sorted[i]); + if(diff<minDiff)minDiff = diff; + } + } + else{ + throw new IllegalArgumentException("Minimum difference may only be returned as the same type as the type of the internal array - you are trying to return as byte or Byte the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return minimum difference + public Byte minimumDifference_as_Byte(){ + return this.getMinimumDifference_as_Byte(); + } + + public Byte getMinimumDifference_as_Byte(){ + return new Byte(this.getMinimumDifference_as_byte()); + } + + // return minimum difference + public BigDecimal minimumDifference_as_BigDecimal(){ + return this.getMinimumDifference_as_BigDecimal(); + } + + public BigDecimal getMinimumDifference_as_BigDecimal(){ + BigDecimal diff = BigDecimal.ZERO; + if(this.type==12){ + ArrayMaths am = this.sort(); + BigDecimal[] sorted = am.getArray_as_BigDecimal(); + diff = sorted[1].subtract(sorted[0]); + BigDecimal minDiff = diff; + for(int i=1; i<this.length-1; i++){ + diff = (sorted[i+1].subtract(sorted[i])); + if(diff.compareTo(minDiff)==-1)minDiff = diff; + } + sorted = null; + minDiff = null; + } + else{ + throw new IllegalArgumentException("Minimum difference may only be returned as the same type as the type of the internal array - you are trying to return as BigDecimal the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // return minimum difference + public BigInteger minimumDifference_as_BigInteger(){ + return this.getMinimumDifference_as_BigInteger(); + } + + public BigInteger getMinimumDifference_as_BigInteger(){ + BigInteger diff = BigInteger.ZERO; + if(this.type==12){ + ArrayMaths am = this.sort(); + BigInteger[] sorted = am.getArray_as_BigInteger(); + diff = sorted[1].subtract(sorted[0]); + BigInteger minDiff = diff; + for(int i=1; i<this.length-1; i++){ + diff = (sorted[i+1].subtract(sorted[i])); + if(diff.compareTo(minDiff)==-1)minDiff = diff; + } + sorted = null; + minDiff = null; + } + else{ + throw new IllegalArgumentException("Minimum difference may only be returned as the same type as the type of the internal array - you are trying to return as BigInteger the difference for a " + this.typeName[this.type] +"[] array"); + } + return diff; + } + + // Print array to screen with no line returns + public void print(){ + switch(this.type){ + case 0: + case 1: Double[] dd = getArray_as_Double(); + PrintToScreen.print(dd); + break; + case 2: + case 3: Float[] ff = getArray_as_Float(); + PrintToScreen.print(ff); + break; + case 4: + case 5: Long[] ll = getArray_as_Long(); + PrintToScreen.print(ll); + break; + case 6: + case 7: Integer[] ii = getArray_as_Integer(); + PrintToScreen.print(ii); + break; + case 8: + case 9: Short[] ss = getArray_as_Short(); + PrintToScreen.print(ss); + break; + case 10: + case 11: Byte[] bb = getArray_as_Byte(); + PrintToScreen.print(bb); + break; + case 12: BigDecimal[] bd = getArray_as_BigDecimal(); + PrintToScreen.print(bd); + bd = null; + break; + case 13: BigInteger[] bi = getArray_as_BigInteger(); + PrintToScreen.print(bi); + bi = null; + break; + case 14: Complex[] cc = getArray_as_Complex(); + PrintToScreen.print(cc); + break; + case 15: Phasor[] pp = getArray_as_Phasor(); + PrintToScreen.print(pp); + break; + case 16: + case 17: Character[] ct = getArray_as_Character(); + PrintToScreen.print(ct); + break; + case 18: String[] st = getArray_as_String(); + PrintToScreen.print(st); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + + // Print array to screen with line returns + public void println(){ + switch(this.type){ + case 0: + case 1: Double[] dd = getArray_as_Double(); + PrintToScreen.println(dd); + break; + case 2: + case 3: Float[] ff = getArray_as_Float(); + PrintToScreen.println(ff); + break; + case 4: + case 5: Long[] ll = getArray_as_Long(); + PrintToScreen.println(ll); + break; + case 6: + case 7: Integer[] ii = getArray_as_Integer(); + PrintToScreen.println(ii); + break; + case 8: + case 9: Short[] ss = getArray_as_Short(); + PrintToScreen.println(ss); + break; + case 10: + case 11: Byte[] bb = getArray_as_Byte(); + PrintToScreen.println(bb); + break; + case 12: BigDecimal[] bd = getArray_as_BigDecimal(); + PrintToScreen.println(bd); + bd = null; + break; + case 13: BigInteger[] bi = getArray_as_BigInteger(); + PrintToScreen.println(bi); + bi = null; + break; + case 14: Complex[] cc = getArray_as_Complex(); + PrintToScreen.println(cc); + break; + case 15: Phasor[] pp = getArray_as_Phasor(); + PrintToScreen.println(pp); + break; + case 16: + case 17: Character[] ct = getArray_as_Character(); + PrintToScreen.println(ct); + break; + case 18: String[] st = getArray_as_String(); + PrintToScreen.println(st); + break; + default: throw new IllegalArgumentException("Data type not identified by this method"); + } + } + + // Convert array to Double if not Complex, Phasor, BigDecimal or BigInteger + // Convert to BigDecimal if BigInteger + // Convert Phasor to Complex + public void convertToHighest(){ + switch(this.type){ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 17: + case 18: Double[] dd = this.getArray_as_Double(); + this.array.clear(); + for(int i=0; i<this.length; i++)this.array.add(dd[i]); + this.type = 1; + break; + case 12: + case 13: BigDecimal[] bd = this.getArray_as_BigDecimal(); + this.array.clear(); + for(int i=0; i<this.length; i++)this.array.add(bd[i]); + this.type = 12; + bd = null; + break; + case 14: + case 15: Complex[] cc = this.getArray_as_Complex(); + this.array.clear(); + for(int i=0; i<this.length; i++)this.array.add(cc[i]); + this.type = 14; + break; + + } + } + + // Returns an instance of Stat in which all the instance variable common to the sub-class Stat and the super-class ArrayMaths + // are set to the values of this instance of ArrayMaths after conversion: + // convert array to Double if not Complex, Phasor, BigDecimal or BigInteger + // convert to BigDecimal if BigInteger + // convert Phasor to Complexof + public Stat toStat(){ + this.convertToHighest(); + return this.statCopy(); + } + + // plot the array + public void plot(int n){ + if(n>2)throw new IllegalArgumentException("Argument n, " + n +", must be less than 3"); + + double[] xAxis = new double[this.length]; + for(int i=0; i<this.length; i++)xAxis[i] = i; + double[] yAxis = this.getArray_as_double(); + + + PlotGraph pg = new PlotGraph(xAxis, yAxis); + pg.setGraphTitle("ArrayMaths plot method"); + pg.setXaxisLegend("Array element index"); + pg.setYaxisLegend("Array element value"); + pg.setPoint(1); + switch(n){ + case 0: pg.setLine(0); + pg.setGraphTitle2("Points only - no line"); + break; + case 1: pg.setLine(3); + pg.setGraphTitle2("Points joined by straight lines"); + break; + case 2: pg.setLine(1); + pg.setGraphTitle2("Points joined by cubic spline interpolated line"); + break; + default: throw new IllegalArgumentException("Should not be possible to get here!!!"); + } + pg.plot(); + } +} + + + + + + + diff --git a/src/main/java/flanagan/math/BetaFunct.java b/src/main/java/flanagan/math/BetaFunct.java new file mode 100644 index 0000000000000000000000000000000000000000..4f1833b071fb8a356958db080576ed21b25d8823 --- /dev/null +++ b/src/main/java/flanagan/math/BetaFunct.java @@ -0,0 +1,19 @@ +package flanagan.math; + +import flanagan.analysis.Stat; +import flanagan.roots.RealRootFunction; + +// Class to evaluate the Beta distribution function +public class BetaFunct implements RealRootFunction { + public double alpha = 0.0D; + public double beta = 0.0D; + public double min = 0.0D; + public double max = 0.0D; + public double cfd = 0.0D; + + public double function(double x){ + double y = cfd - Stat.betaCDF(min, max, alpha, beta, x); + + return y; + } +} diff --git a/src/main/java/flanagan/math/ChiSquareFunct.java b/src/main/java/flanagan/math/ChiSquareFunct.java new file mode 100644 index 0000000000000000000000000000000000000000..7ea52457bbf099e1a9f2a17176e2a603f69f7eb0 --- /dev/null +++ b/src/main/java/flanagan/math/ChiSquareFunct.java @@ -0,0 +1,18 @@ +package flanagan.math; + +import flanagan.analysis.Stat; +import flanagan.roots.RealRootFunction; + +// Class to evaluate the chi-square distribution function +public class ChiSquareFunct implements RealRootFunction { + + public double cfd = 0.0D; + public int nu = 0; + + public double function(double x){ + + double y = cfd - Stat.chiSquareCDF(x, nu); + + return y; + } +} diff --git a/src/main/java/flanagan/math/Conv.java b/src/main/java/flanagan/math/Conv.java new file mode 100755 index 0000000000000000000000000000000000000000..c675416b0c518551150cafe3a7198cc51f000499 --- /dev/null +++ b/src/main/java/flanagan/math/Conv.java @@ -0,0 +1,1367 @@ +/* +* Class Conv +* +* USAGE: Methods for: +* Recasting variable type with exception throwing not present in standard java recasts +* Conversion of physical entities from one set of units to another +* Copying of an object +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: April 2008 +* AMENDED: September 2009 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* http://www.ee.ucl.ac.uk/~mflanaga/java/Conv.html +* +* Copyright (c) 2008 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.math; + +import java.math.*; +import java.io.IOException; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectInputStream; + +import flanagan.math.Fmath; +import flanagan.complex.Complex; +import flanagan.circuits.Phasor; + + +public class Conv{ + + private static int type = -1; // 0 double, 1 Double, 2 long, 3 Long, 4 float, 5 Float, 6 int, 7 Integer, 8 short, 9 Short, 10 byte, 11 Byte + // 12 BigDecimal, 13 BigInteger, 14 Complex, 15 Phasor, 16 char, 17 Character, 18 String + private static String[] typeName = {"double", "Double", "long", "Long", "float", "Float", "int", "Integer", "short", "Short", "byte", "Byte", "BigDecimal", "BigInteger", "Complex", "Phasor", "char", "Character", "String"}; + + private static double max_float_as_double = (double)Float.MAX_VALUE; + private static double max_long_as_double = (double)Long.MAX_VALUE; + private static double max_long_as_float = (float)Long.MAX_VALUE; + private static double max_int_as_double = (double)Integer.MAX_VALUE; + private static double max_int_as_float = (float)Integer.MAX_VALUE; + private static double max_int_as_long = (long)Integer.MAX_VALUE; + private static double max_short_as_double = (double)Short.MAX_VALUE; + private static double max_short_as_long = (long)Short.MAX_VALUE; + private static double max_short_as_float = (float)Short.MAX_VALUE; + private static double max_short_as_int = (int)Short.MAX_VALUE; + private static double max_byte_as_double = (double)Byte.MAX_VALUE; + private static double max_byte_as_float = (float)Byte.MAX_VALUE; + private static double max_byte_as_long = (long)Byte.MAX_VALUE; + private static double max_byte_as_int = (int)Byte.MAX_VALUE; + private static double max_byte_as_short = (short)Byte.MAX_VALUE; + + private static boolean suppressMessage = false; // if true lack of precision messages are suppressed + private static boolean suppressMessageAM = false; // for use with ArrayMaths - allows suppression for all instances of ArrayMaths + + // CONSTRUCTORS + public Conv(){ + } + + // LOSS OF PRECISION MESSAGE + // Suppress loss of precision messages + public static void suppressMessages(){ + Conv.suppressMessage = true; + } + + // Restore loss of precision messages + public static void restoreMessages(){ + if(!Conv.suppressMessageAM)Conv.suppressMessage = false; + } + + // For use of ArrayMaths - suppression for all ArrayMaths instances + public static void suppressMessagesAM(){ + Conv.suppressMessageAM = true; + } + + // For use of ArrayMaths - restore total loss of precision messages + public static void restoreMessagesAM(){ + Conv.suppressMessageAM = false; + } + + // RECAST + // double and Double -> . . . + public static float convert_double_to_float(double x){ + if(x>max_float_as_double)throw new IllegalArgumentException("double is too large to be recast as float"); + if(!suppressMessage)System.out.println("Class Conv: method convert_double_to_float: possible loss of precision"); + return (new Double(x)).floatValue(); + } + + public static Float convert_double_to_Float(double x){ + if(x>max_float_as_double)throw new IllegalArgumentException("double is too large to be recast as float"); + if(!suppressMessage)System.out.println("Class Conv: method convert_double_to_Float: possible loss of precision"); + return new Float((new Double(x)).floatValue()); + } + + public static float convert_Double_to_float(Double xx){ + double x = xx.doubleValue(); + if(x>max_float_as_double)throw new IllegalArgumentException("Double is too large to be recast as float"); + if(!suppressMessage)System.out.println("Class Conv: method convert_Double_to_float: possible loss of precision"); + return xx.floatValue(); + } + + public static Float convert_Double_to_Float(Double xx){ + double x = xx.doubleValue(); + if(x>max_float_as_double)throw new IllegalArgumentException("Double is too large to be recast as Float"); + if(!suppressMessage)System.out.println("Class Conv: method convert_Double_to_Float: possible loss of precision"); + return new Float(x); + } + + public static long convert_double_to_long(double x){ + if(x>max_long_as_double)throw new IllegalArgumentException("double is too large to be recast as long"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("double is not, arithmetically, an integer"); + return (new Double(x)).longValue(); + } + + public static Long convert_double_to_Long(double x){ + if(x>max_long_as_double)throw new IllegalArgumentException("double is too large to be recast as long"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("double is not, arithmetically, an integer"); + return new Long((new Double(x)).longValue()); + } + + public static long convert_Double_to_long(Double xx){ + double x = xx.doubleValue(); + if(x>max_long_as_double)throw new IllegalArgumentException("Double is too large to be recast as long"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Double is not, arithmetically, an integer"); + return xx.longValue(); + } + + public static Long convert_Double_to_Long(Double xx){ + double x = xx.doubleValue(); + if(x>max_long_as_double)throw new IllegalArgumentException("Double is too large to be recast as Long"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Double is not, arithmetically, an integer"); + return new Long(xx.longValue()); + } + + public static int convert_double_to_int(double x){ + if(x>max_int_as_double)throw new IllegalArgumentException("double is too large to be recast as int"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("double is not, arithmetically, an integer"); + return (new Double(x)).intValue(); + } + + public static Integer convert_double_to_Integer(double x){ + if(x>max_int_as_double)throw new IllegalArgumentException("double is too large to be recast as int"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("double is not, arithmetically, an integer"); + return new Integer((new Double(x)).intValue()); + } + + public static int convert_Double_to_int(Double xx){ + double x = xx.doubleValue(); + if(x>max_int_as_double)throw new IllegalArgumentException("Double is too large to be recast as int"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Double is not, arithmetically, an integer"); + return xx.intValue(); + } + + public static Integer convert_Double_to_Integer(Double xx){ + double x = xx.doubleValue(); + if(x>max_int_as_double)throw new IllegalArgumentException("Double is too large to be recast as Integer"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Double is not, arithmetically, an integer"); + return new Integer(xx.intValue()); + } + + public static short convert_double_to_short(double x){ + if(x>max_short_as_double)throw new IllegalArgumentException("double is too large to be recast as short"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("double is not, arithmetically, an integer"); + return (new Double(x)).shortValue(); + } + + public static Short convert_double_to_Short(double x){ + if(x>max_short_as_double)throw new IllegalArgumentException("double is too large to be recast as short"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("double is not, arithmetically, an integer"); + return new Short((new Double(x)).shortValue()); + } + + public static short convert_Double_to_short(Double xx){ + double x = xx.doubleValue(); + if(x>max_short_as_double)throw new IllegalArgumentException("Double is too large to be recast as short"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Double is not, arithmetically, an integer"); + return xx.shortValue(); + } + + public static Short convert_Double_to_Short(Double xx){ + double x = xx.doubleValue(); + if(x>max_short_as_double)throw new IllegalArgumentException("Double is too large to be recast as Short"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Double is not, arithmetically, an integer"); + return new Short(xx.shortValue()); + } + + public static byte convert_double_to_byte(double x){ + if(x>max_byte_as_double)throw new IllegalArgumentException("double is too large to be recast as byte"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("double is not, arithmetically, an integer"); + return (new Double(x)).byteValue(); + } + + public static Byte convert_double_to_Byte(double x){ + if(x>max_byte_as_double)throw new IllegalArgumentException("double is too large to be recast as byte"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("double is not, arithmetically, an integer"); + return new Byte((new Double(x)).byteValue()); + } + + public static byte convert_Double_to_byte(Double xx){ + double x = xx.doubleValue(); + if(x>max_byte_as_double)throw new IllegalArgumentException("Double is too large to be recast as byte"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Double is not, arithmetically, an integer"); + return xx.byteValue(); + } + + public static Byte convert_Double_to_Byte(Double xx){ + double x = xx.doubleValue(); + if(x>max_byte_as_double)throw new IllegalArgumentException("Double is too large to be recast as Byte"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Double is not, arithmetically, an integer"); + return new Byte(xx.byteValue()); + } + + public static BigDecimal convert_double_to_BigDecimal(double x){ + return new BigDecimal(x); + } + + public static BigDecimal convert_Double_to_BigDecimal(Double xx){ + return new BigDecimal(xx.doubleValue()); + } + + public static BigInteger convert_double_to_BigInteger(double x){ + if(!Fmath.isInteger(x))throw new IllegalArgumentException("double is not, arithmetically, an integer"); + return new BigInteger(Double.toString(x)); + } + + public static BigInteger convert_Double_to_BigInteger(Double xx){ + double x = xx.doubleValue(); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("double is not, arithmetically, an integer"); + return new BigInteger(Double.toString(x)); + } + + // float and Float -> . . . + public static double convert_float_to_double(float x){ + return (new Float(x)).doubleValue(); + } + + public static Double convert_float_to_Double(float x){ + return new Double((new Float(x)).doubleValue()); + } + + public static double convert_Float_to_double(Float xx){ + return xx.doubleValue(); + } + + public static Double convert_Float_to_Double(Float xx){ + return new Double(xx.doubleValue()); + } + + public static long convert_float_to_long(float x){ + if(x>max_long_as_float)throw new IllegalArgumentException("float is too large to be recast as long"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("float is not, arithmetically, an integer"); + return (new Float(x)).longValue(); + } + + public static Long convert_float_to_Long(float x){ + if(x>max_long_as_float)throw new IllegalArgumentException("float is too large to be recast as long"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("float is not, arithmetically, an integer"); + return new Long((new Float(x)).longValue()); + } + + public static long convert_Float_to_long(Float xx){ + float x = xx.floatValue(); + if(x>max_long_as_float)throw new IllegalArgumentException("Float is too large to be recast as long"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Float is not, arithmetically, an integer"); + return xx.longValue(); + } + + public static Long convert_Float_to_Long(Float xx){ + float x = xx.floatValue(); + if(x>max_long_as_float)throw new IllegalArgumentException("Float is too large to be recast as Long"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Float is not, arithmetically, an integer"); + return new Long(xx.longValue()); + } + + public static int convert_float_to_int(float x){ + if(x>max_int_as_float)throw new IllegalArgumentException("double is too large to be recast as int"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("double is not, arithmetically, an integer"); + return (new Float(x)).intValue(); + } + + public static Integer convert_float_to_Integer(float x){ + if(x>max_int_as_float)throw new IllegalArgumentException("float is too large to be recast as int"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("float is not, arithmetically, an integer"); + return new Integer((new Float(x)).intValue()); + } + + public static int convert_Float_to_int(Float xx){ + float x = xx.floatValue(); + if(x>max_int_as_float)throw new IllegalArgumentException("Float is too large to be recast as int"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Float is not, arithmetically, an integer"); + return xx.intValue(); + } + + public static Integer convert_Float_to_Integer(Float xx){ + float x = xx.floatValue(); + if(x>max_int_as_float)throw new IllegalArgumentException("Float is too large to be recast as Integer"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Float is not, arithmetically, an integer"); + return new Integer(xx.intValue()); + } + + public static short convert_float_to_short(float x){ + if(x>max_short_as_float)throw new IllegalArgumentException("float is too large to be recast as short"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("float is not, arithmetically, an integer"); + return (new Float(x)).shortValue(); + } + + public static Short convert_float_to_Short(float x){ + if(x>max_short_as_float)throw new IllegalArgumentException("float is too large to be recast as short"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("float is not, arithmetically, an integer"); + return new Short((new Float(x)).shortValue()); + } + + public static short convert_Float_to_short(Float xx){ + float x = xx.floatValue(); + if(x>max_short_as_float)throw new IllegalArgumentException("Float is too large to be recast as short"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Float is not, arithmetically, an integer"); + return xx.shortValue(); + } + + public static Short convert_Float_to_Short(Float xx){ + float x = xx.floatValue(); + if(x>max_short_as_float)throw new IllegalArgumentException("Float is too large to be recast as Short"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Float is not, arithmetically, an integer"); + return new Short(xx.shortValue()); + } + + public static byte convert_float_to_byte(float x){ + if(x>max_byte_as_float)throw new IllegalArgumentException("float is too large to be recast as byte"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("float is not, arithmetically, an integer"); + return (new Float(x)).byteValue(); + } + + public static Byte convert_float_to_Byte(float x){ + if(x>max_byte_as_float)throw new IllegalArgumentException("float is too large to be recast as byte"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("float is not, arithmetically, an integer"); + return new Byte((new Float(x)).byteValue()); + } + + public static byte convert_Float_to_byte(Float xx){ + float x = xx.floatValue(); + if(x>max_byte_as_float)throw new IllegalArgumentException("Float is too large to be recast as byte"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Float is not, arithmetically, an integer"); + return xx.byteValue(); + } + + public static Byte convert_Float_to_Byte(Float xx){ + float x = xx.floatValue(); + if(x>max_byte_as_float)throw new IllegalArgumentException("Float is too large to be recast as Byte"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Float is not, arithmetically, an integer"); + return new Byte(xx.byteValue()); + } + + public static BigDecimal convert_float_to_BigDecimal(float x){ + return new BigDecimal((double)x); + } + + public static BigDecimal convert_Float_to_BigDecimal(Float xx){ + return new BigDecimal(xx.doubleValue()); + } + + public static BigInteger convert_double_to_BigInteger(float x){ + if(!Fmath.isInteger(x))throw new IllegalArgumentException("float is not, arithmetically, an integer"); + return new BigInteger(Float.toString(x)); + } + + public static BigInteger convert_Float_to_BigInteger(Float xx){ + double x = xx.doubleValue(); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("Float is not, arithmetically, an integer"); + return new BigInteger(Double.toString(x)); + } + + + // long and Long -> . . . + public static double convert_long_to_double(long x){ + if(!suppressMessage)System.out.println("Class Conv: method convert_long_to_double: possible loss of precision"); + return (new Long(x)).doubleValue(); + } + + public static Double convert_long_to_Double(long x){ + if(!suppressMessage)System.out.println("Class Conv: method convert_long_to_Double: possible loss of precision"); + return new Double((new Long(x)).doubleValue()); + } + + public static double convert_Long_to_double(Long xx){ + if(!suppressMessage)System.out.println("Class Conv: method convert_Long_to_double: possible loss of precision"); + return xx.doubleValue(); + } + + public static Double convert_Long_to_Double(Long xx){ + if(!suppressMessage)System.out.println("Class Conv: method convert_Long_to_Double: possible loss of precision"); + return new Double(xx.doubleValue()); + } + + public static float convert_long_to_float(long x){ + if(!suppressMessage)System.out.println("Class Conv: method convert_long_to_float: possible loss of precision"); + return (new Long(x)).floatValue(); + } + + public static Float convert_long_to_Float(long x){ + if(!suppressMessage)System.out.println("Class Conv: method convert_long_to_Float: possible loss of precision"); + return new Float((new Long(x)).floatValue()); + } + + public static float convert_Long_to_float(Long xx){ + if(!suppressMessage)System.out.println("Class Conv: method convert_Long_to_float: possible loss of precision"); + return xx.floatValue(); + } + + public static Float convert_Long_to_Float(Long xx){ + if(!suppressMessage)System.out.println("Class Conv: method convert_Long_to_Float: possible loss of precision"); + return new Float(xx.floatValue()); + } + + public static int convert_long_to_int(long x){ + if(x>max_int_as_long)throw new IllegalArgumentException("long is too large to be recast as int"); + return (new Float(x)).intValue(); + } + + public static Integer convert_long_to_Integer(long x){ + if(x>max_int_as_long)throw new IllegalArgumentException("long is too large to be recast as Integer"); + return new Integer((new Long(x)).intValue()); + } + + public static int convert_Long_to_int(Long xx){ + long x = xx.longValue(); + if(x>max_int_as_long)throw new IllegalArgumentException("Long is too large to be recast as int"); + return xx.intValue(); + } + + public static Integer convert_Long_to_Integer(Long xx){ + long x = xx.longValue(); + if(x>max_int_as_long)throw new IllegalArgumentException("Long is too large to be recast as Integer"); + return new Integer(xx.intValue()); + } + + public static short convert_long_to_short(long x){ + if(x>max_short_as_long)throw new IllegalArgumentException("long is too large to be recast as short"); + return (new Long(x)).shortValue(); + } + + public static Short convert_long_to_Short(long x){ + if(x>max_short_as_long)throw new IllegalArgumentException("long is too large to be recast as Short"); + return new Short((new Long(x)).shortValue()); + } + + public static short convert_Long_to_short(Long xx){ + long x = xx.longValue(); + if(x>max_short_as_long)throw new IllegalArgumentException("Long is too large to be recast as short"); + return xx.shortValue(); + } + + public static Short convert_Long_to_Short(Long xx){ + long x = xx.longValue(); + if(x>max_short_as_long)throw new IllegalArgumentException("Long is too large to be recast as Short"); + return new Short(xx.shortValue()); + } + + public static byte convert_long_to_byte(long x){ + if(x>max_byte_as_long)throw new IllegalArgumentException("long is too large to be recast as byte"); + return (new Long(x)).byteValue(); + } + + public static Byte convert_long_to_Byte(long x){ + if(x>max_byte_as_long)throw new IllegalArgumentException("long is too large to be recast as Byte"); + return new Byte((new Long(x)).byteValue()); + } + + public static byte convert_Long_to_byte(Long xx){ + long x = xx.longValue(); + if(x>max_byte_as_long)throw new IllegalArgumentException("Long is too large to be recast as byte"); + return xx.byteValue(); + } + + public static Byte convert_Long_to_Byte(Long xx){ + long x = xx.longValue(); + if(x>max_byte_as_long)throw new IllegalArgumentException("Long is too large to be recast as Byte"); + return new Byte(xx.byteValue()); + } + + public static BigDecimal convert_long_to_BigDecimal(long x){ + return new BigDecimal((new Long(x)).toString()); + } + + public static BigDecimal convert_Long_to_BigDecimal(Long xx){ + return new BigDecimal(xx.toString()); + } + + public static BigInteger convert_long_to_BigInteger(long x){ + return new BigInteger(Long.toString(x)); + } + + public static BigInteger convert_Long_to_BigInteger(Long xx){ + double x = xx.doubleValue(); + return new BigInteger(xx.toString()); + } + + // int and Integer -> . . . + public static double convert_int_to_double(int x){ + return (new Integer(x)).doubleValue(); + } + + public static Double convert_int_to_Double(int x){ + return new Double((new Integer(x)).doubleValue()); + } + + public static double convert_Integer_to_double(Integer xx){ + return xx.doubleValue(); + } + + public static Double convert_Integer_to_Double(Integer xx){ + return new Double(xx.doubleValue()); + } + + public static float convert_int_to_float(int x){ + if(!suppressMessage)System.out.println("Class Conv: method convert_int_to_float: possible loss of precision"); + return (new Integer(x)).floatValue(); + } + + public static Float convert_int_to_Float(int x){ + if(!suppressMessage)System.out.println("Class Conv: method convert_int_to_Float: possible loss of precision"); + return new Float((new Integer(x)).floatValue()); + } + + public static float convert_Integer_to_float(Integer xx){ + if(!suppressMessage)System.out.println("Class Conv: method convert_Integer_to_float: possible loss of precision"); + return xx.floatValue(); + } + + public static Float convert_Integer_to_Float(Integer xx){ + if(!suppressMessage)System.out.println("Class Conv: method convert_Integer_to_Float: possible loss of precision"); + return new Float(xx.floatValue()); + } + + public static long convert_int_to_long(int x){ + return (new Integer(x)).longValue(); + } + + public static Long convert_int_to_Long(int x){ + return new Long((new Integer(x)).longValue()); + } + + public static long convert_Integer_to_long(Integer xx){ + return xx.longValue(); + } + + public static Long convert_Integer_to_Long(Integer xx){ + return new Long(xx.longValue()); + } + + public static short convert_int_to_short(int x){ + if(x>max_short_as_int)throw new IllegalArgumentException("int is too large to be recast as short"); + return (new Integer(x)).shortValue(); + } + + public static Short convert_int_to_Short(int x){ + if(x>max_short_as_int)throw new IllegalArgumentException("int is too large to be recast as Short"); + return new Short((new Integer(x)).shortValue()); + } + + public static short convert_Integer_to_short(Integer xx){ + int x = xx.intValue(); + if(x>max_short_as_int)throw new IllegalArgumentException("Integer is too large to be recast as short"); + return xx.shortValue(); + } + + public static Short convert_Integer_to_Short(Integer xx){ + int x = xx.intValue(); + if(x>max_short_as_int)throw new IllegalArgumentException("Integer is too large to be recast as Short"); + return new Short(xx.shortValue()); + } + + public static byte convert_int_to_byte(int x){ + if(x>max_byte_as_int)throw new IllegalArgumentException("int is too large to be recast as byte"); + return (new Integer(x)).byteValue(); + } + + public static Byte convert_int_to_Byte(int x){ + if(x>max_byte_as_int)throw new IllegalArgumentException("int is too large to be recast as Byte"); + return new Byte((new Integer(x)).byteValue()); + } + + public static byte convert_Integer_to_byte(Integer xx){ + int x = xx.intValue(); + if(x>max_byte_as_int)throw new IllegalArgumentException("Integer is too large to be recast as byte"); + return xx.byteValue(); + } + + public static Byte convert_Integer_to_Byte(Integer xx){ + int x = xx.intValue(); + if(x>max_byte_as_int)throw new IllegalArgumentException("Integer is too large to be recast as Byte"); + return new Byte(xx.byteValue()); + } + + public static BigDecimal convert_int_to_BigDecimal(int x){ + return new BigDecimal((new Integer(x)).toString()); + } + + public static BigDecimal convert_Integer_to_BigDecimal(Integer xx){ + return new BigDecimal(xx.toString()); + } + + public static BigInteger convert_int_to_BigInteger(int x){ + return new BigInteger(Long.toString(x)); + } + + public static BigInteger convert_Integer_to_BigInteger(Integer xx){ + return new BigInteger(xx.toString()); + } + + // short and Short -> . . . + public static double convert_short_to_double(short x){ + return (new Short(x)).doubleValue(); + } + + public static Double convert_short_to_Double(short x){ + return new Double((new Short(x)).doubleValue()); + } + + public static double convert_Short_to_double(Short xx){ + return xx.doubleValue(); + } + + public static Double convert_Short_to_Double(Short xx){ + return new Double(xx.doubleValue()); + } + + public static float convert_short_to_float(short x){ + return (new Short(x)).floatValue(); + } + + public static Float convert_short_to_Float(short x){ + return new Float((new Short(x)).floatValue()); + } + + public static float convert_Short_to_float(Short xx){ + return xx.floatValue(); + } + + public static Float convert_Short_to_Float(Short xx){ + return new Float(xx.floatValue()); + } + + public static long convert_short_to_long(short x){ + return (new Short(x)).longValue(); + } + + public static Long convert_short_to_Long(short x){ + return new Long((new Short(x)).longValue()); + } + + public static long convert_Short_to_long(Short xx){ + return xx.longValue(); + } + + public static Long convert_Short_to_Long(Short xx){ + return new Long(xx.longValue()); + } + + public static int convert_short_to_int(short x){ + return (new Short(x)).intValue(); + } + + public static Integer convert_short_to_Integer(short x){ + return new Integer((new Short(x)).intValue()); + } + + public static int convert_Short_to_int(Short xx){ + return xx.intValue(); + } + + public static Integer convert_Short_to_Integer(Short xx){ + return new Integer(xx.intValue()); + } + + public static byte convert_short_to_byte(short x){ + if(x>max_byte_as_short)throw new IllegalArgumentException("short is too large to be recast as byte"); + return (new Short(x)).byteValue(); + } + + public static Byte convert_short_to_Byte(short x){ + if(x>max_byte_as_short)throw new IllegalArgumentException("short is too large to be recast as Byte"); + return new Byte((new Short(x)).byteValue()); + } + + public static byte convert_Short_to_byte(Short xx){ + int x = xx.shortValue(); + if(x>max_byte_as_short)throw new IllegalArgumentException("Short is too large to be recast as byte"); + return xx.byteValue(); + } + + public static Byte convert_Short_to_Byte(Short xx){ + int x = xx.shortValue(); + if(x>max_byte_as_short)throw new IllegalArgumentException("Short is too large to be recast as Byte"); + return new Byte(xx.byteValue()); + } + + public static BigDecimal convert_short_to_BigDecimal(short x){ + return new BigDecimal((new Short(x)).toString()); + } + + public static BigDecimal convert_Short_to_BigDecimal(Short xx){ + return new BigDecimal(xx.toString()); + } + + public static BigInteger convert_short_to_BigInteger(short x){ + return new BigInteger(Short.toString(x)); + } + + public static BigInteger convert_Short_to_BigInteger(Short xx){ + return new BigInteger(xx.toString()); + } + + // byte and Byte -> . . . + public static double convert_byte_to_double(byte x){ + return (new Byte(x)).doubleValue(); + } + + public static Double convert_byte_to_Double(byte x){ + return new Double((new Byte(x)).doubleValue()); + } + + public static double convert_Byte_to_double(Byte xx){ + return xx.doubleValue(); + } + + public static Double convert_Byte_to_Double(Byte xx){ + return new Double(xx.doubleValue()); + } + + public static float convert_byte_to_float(byte x){ + return (new Byte(x)).floatValue(); + } + + public static Float convert_byte_to_Float(byte x){ + return new Float((new Byte(x)).floatValue()); + } + + public static float convert_Byte_to_float(Byte xx){ + return xx.floatValue(); + } + + public static Float convert_Byte_to_Float(Byte xx){ + return new Float(xx.floatValue()); + } + + public static long convert_byte_to_long(byte x){ + return (new Byte(x)).longValue(); + } + + public static Long convert_byte_to_Long(byte x){ + return new Long((new Byte(x)).longValue()); + } + + public static long convert_Byte_to_long(Byte xx){ + return xx.longValue(); + } + + public static Long convert_Byte_to_Long(Byte xx){ + return new Long(xx.longValue()); + } + + public static int convert_byte_to_int(byte x){ + return (new Byte(x)).intValue(); + } + + public static Integer convert_byte_to_Integer(byte x){ + return new Integer((new Byte(x)).intValue()); + } + + public static int convert_Byte_to_int(Byte xx){ + return xx.intValue(); + } + + public static Integer convert_Byte_to_Integer(Byte xx){ + return new Integer(xx.intValue()); + } + + public static short convert_byte_to_short(byte x){ + return (new Byte(x)).shortValue(); + } + + public static Short convert_byte_to_Short(byte x){ + return new Short((new Byte(x)).shortValue()); + } + + public static short convert_Byte_to_short(Byte xx){ + return xx.shortValue(); + } + + public static Short convert_Byte_to_Short(Byte xx){ + return new Short(xx.shortValue()); + } + + public static BigDecimal convert_byte_to_BigDecimal(byte x){ + return new BigDecimal((new Byte(x)).toString()); + } + + public static BigDecimal convert_Byte_to_BigDecimal(Byte xx){ + return new BigDecimal(xx.toString()); + } + + public static BigInteger convert_byte_to_BigInteger(byte x){ + return new BigInteger(Byte.toString(x)); + } + + public static BigInteger convert_Byte_to_BigInteger(Byte xx){ + return new BigInteger(xx.toString()); + } + + + // BigDecimal -> . . . + public static double convert_BigDecimal_to_double(BigDecimal xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigDecimal is too large to be recast as double"); + if(!suppressMessage)System.out.println("Class Conv: method convert_BigDecimal_to_double: possible loss of precision"); + return x; + } + + public static Double convert_BigDecimal_to_Double(BigDecimal xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigDecimal is too large to be recast as double"); + if(!suppressMessage)System.out.println("Class Conv: method convert_BigDecimal_to_double: possible loss of precision"); + return new Double(x); + } + + public static float convert_BigDecimal_to_float(BigDecimal xx){ + float x = xx.floatValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigDecimal is too large to be recast as float"); + if(!suppressMessage)System.out.println("Class Conv: method convert_BigDecimal_to_float: possible loss of precision"); + return x; + } + + public static Float convert_BigDecimal_to_Float(BigDecimal xx){ + float x = xx.floatValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigDecimal is too large to be recast as float"); + if(!suppressMessage)System.out.println("Class Conv: method convert_BigDecimal_to_float: possible loss of precision"); + return new Float(x); + } + + public static long convert_BigDecimal_to_long(BigDecimal xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigDecimal is too large to be recast as long"); + if(x>max_long_as_double)throw new IllegalArgumentException("BigDecimal is too large to be recast as long"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("BigDecimal is not, arithmetically, an integer"); + return xx.longValue(); + } + + public static Long convert_BigDecimal_to_Long(BigDecimal xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigDecimal is too large to be recast as Long"); + if(x>max_long_as_double)throw new IllegalArgumentException("BigDecimal is too large to be recast as Long"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("BigDecimal is not, arithmetically, an integer"); + return new Long(xx.longValue()); + } + + public static int convert_BigDecimal_to_int(BigDecimal xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigDecimal is too large to be recast as int"); + if(x>max_int_as_double)throw new IllegalArgumentException("BigDecimal is too large to be recast as int"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("BigDecimal is not, arithmetically, an integer"); + return xx.intValue(); + } + + public static Integer convert_BigDecimal_to_Integer(BigDecimal xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigDecimal is too large to be recast as Integer"); + if(x>max_int_as_double)throw new IllegalArgumentException("BigDecimal is too large to be recast as Integer"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("BigDecimal is not, arithmetically, an integer"); + return new Integer(xx.intValue()); + } + + public static short convert_BigDecimal_to_short(BigDecimal xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigDecimal is too large to be recast as short"); + if(x>max_short_as_double)throw new IllegalArgumentException("BigDecimal is too large to be recast as short"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("BigDecimal is not, arithmetically, an integer"); + return xx.shortValue(); + } + + public static Short convert_BigDecimal_to_Short(BigDecimal xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigDecimal is too large to be recast as Short"); + if(x>max_short_as_double)throw new IllegalArgumentException("BigDecimal is too large to be recast as Short"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("BigDecimal is not, arithmetically, an integer"); + return new Short(xx.shortValue()); + } + + public static byte convert_BigDecimal_to_byte(BigDecimal xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigDecimal is too large to be recast as byte"); + if(x>max_byte_as_double)throw new IllegalArgumentException("BigDecimal is too large to be recast as byte"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("BigDecimal is not, arithmetically, an integer"); + return xx.byteValue(); + } + + public static Byte convert_BigDecimal_to_Byte(BigDecimal xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigDecimal is too large to be recast as Byte"); + if(x>max_byte_as_double)throw new IllegalArgumentException("BigDecimal is too large to be recast as Byte"); + if(!Fmath.isInteger(x))throw new IllegalArgumentException("BigDecimal is not, arithmetically, an integer"); + return new Byte(xx.byteValue()); + } + + public static BigInteger convert_BigDecimal_to_BigInteger(BigDecimal xx){ + String ss = xx.toString(); + int posDot = ss.indexOf('.'); + int posExp = ss.indexOf('E'); + String tt = null; + + if(posDot==-1){ + return xx.toBigInteger(); + } + else{ + if(posExp==-1){ + tt = ss.substring(posDot+1); + } + else{ + tt = ss.substring(posDot+1, posExp); + } + int n = tt.length(); + boolean test1 = true; + boolean test2 = true; + int ii=0; + while(test1){ + if(tt.charAt(ii)!='0'){ + test1 = false; + test2 = false; + } + else{ + ii++; + if(ii==n)test1 = false; + } + } + if(test2){ + return xx.toBigInteger(); + } + else{ + throw new IllegalArgumentException("BigDecimal is not, arithmetically, an integer"); + } + } + } + + + + // BigInteger -> . . . + public static double convert_BigInteger_to_double(BigInteger xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigInteger is too large to be recast as double"); + if(!suppressMessage)System.out.println("Class Conv: method convert_BigInteger_to_double: possible loss of precision"); + return x; + } + + public static Double convert_BigInteger_to_Double(BigInteger xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigInteger is too large to be recast as double"); + if(!suppressMessage)System.out.println("Class Conv: method convert_BigInteger_to_double: possible loss of precision"); + return new Double(x); + } + + public static float convert_BigInteger_to_float(BigInteger xx){ + float x = xx.floatValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigInteger is too large to be recast as float"); + if(!suppressMessage)System.out.println("Class Conv: method convert_BigInteger_to_float: possible loss of precision"); + return x; + } + + public static Float convert_BigInteger_to_Float(BigInteger xx){ + float x = xx.floatValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigInteger is too large to be recast as float"); + if(!suppressMessage)System.out.println("Class Conv: method convert_BigInteger_to_float: possible loss of precision"); + return new Float(x); + } + + public static long convert_BigInteger_to_long(BigInteger xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigInteger is too large to be recast as long"); + if(x>max_long_as_double)throw new IllegalArgumentException("BigInteger is too large to be recast as long"); + return xx.longValue(); + } + + public static Long convert_BigInteger_to_Long(BigInteger xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigInteger is too large to be recast as Long"); + if(x>max_long_as_double)throw new IllegalArgumentException("BigInteger is too large to be recast as Long"); + return new Long(xx.longValue()); + } + + public static int convert_BigInteger_to_int(BigInteger xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigInteger is too large to be recast as int"); + if(x>max_int_as_double)throw new IllegalArgumentException("BigInteger is too large to be recast as int"); + return xx.intValue(); + } + + public static Integer convert_BigInteger_to_Integer(BigInteger xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigInteger is too large to be recast as Integer"); + if(x>max_int_as_double)throw new IllegalArgumentException("BigInteger is too large to be recast as Integer"); + return new Integer(xx.intValue()); + } + + public static short convert_BigInteger_to_short(BigInteger xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigInteger is too large to be recast as short"); + if(x>max_short_as_double)throw new IllegalArgumentException("BigInteger is too large to be recast as short"); + return xx.shortValue(); + } + + public static Short convert_BigInteger_to_Short(BigInteger xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigInteger is too large to be recast as Short"); + if(x>max_short_as_double)throw new IllegalArgumentException("BigInteger is too large to be recast as Short"); + return new Short(xx.shortValue()); + } + + public static byte convert_BigInteger_to_byte(BigInteger xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigInteger is too large to be recast as byte"); + if(x>max_byte_as_double)throw new IllegalArgumentException("BigInteger is too large to be recast as byte"); + return xx.byteValue(); + } + + public static Byte convert_BigInteger_to_Byte(BigInteger xx){ + double x = xx.doubleValue(); + if(Fmath.isInfinity(x))throw new IllegalArgumentException("BigInteger is too large to be recast as Byte"); + if(x>max_byte_as_double)throw new IllegalArgumentException("BigInteger is too large to be recast as Byte"); + return new Byte(xx.byteValue()); + } + + public static BigDecimal convert_BigInteger_to_BigDecimal(BigInteger xx){ + return new BigDecimal(xx); + } + + // Complex -> Phasor + public static Phasor convert_Complex_to_Phasor(Complex xx){ + double mag = xx.abs(); + double phase = xx.argDeg(); + return new Phasor(mag, phase); + } + + // Phasor -> Complex + public static Complex convert_Phasor_to_Complex(Phasor xx){ + return xx.toComplex(); + } + + // COPY OF AN OBJECT + // An exception will be thrown if an attempt to copy a non-serialisable object is made. + // Taken, with minor changes, from { Java Techniques } + // http://javatechniques.com/blog/ + public static Object copyObject(Object obj) { + Object objCopy = null; + try { + // Write the object out to a byte array + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(obj); + oos.flush(); + oos.close(); + // Make an input stream from the byte array and + // read a copy of the object back in. + ObjectInputStream ois = new ObjectInputStream( + new ByteArrayInputStream(bos.toByteArray())); + objCopy = ois.readObject(); + } + catch(IOException e) { + e.printStackTrace(); + } + catch(ClassNotFoundException cnfe) { + cnfe.printStackTrace(); + } + return objCopy; + } + + // UNIT CONVERSIONS + + // Converts radians to degrees + public static double radToDeg(double rad){ + return rad*180.0D/Math.PI; + } + + // Converts degrees to radians + public static double degToRad(double deg){ + return deg*Math.PI/180.0D; + } + + // Converts frequency (Hz) to radial frequency + public static double frequencyToRadialFrequency(double frequency){ + return 2.0D*Math.PI*frequency; + } + + // Converts radial frequency to frequency (Hz) + public static double radialFrequencyToFrequency(double radial){ + return radial/(2.0D*Math.PI); + } + + // Converts electron volts(eV) to corresponding wavelength in nm + public static double evToNm(double ev){ + return 1e+9*Fmath.C_LIGHT/(-ev*Fmath.Q_ELECTRON/Fmath.H_PLANCK); + } + + // Converts wavelength in nm to matching energy in eV + public static double nmToEv(double nm) + { + return Fmath.C_LIGHT/(-nm*1e-9)*Fmath.H_PLANCK/Fmath.Q_ELECTRON; + } + + // Converts moles per litre to percentage weight by volume + public static double molarToPercentWeightByVol(double molar, double molWeight){ + return molar*molWeight/10.0D; + } + + // Converts percentage weight by volume to moles per litre + public static double percentWeightByVolToMolar(double perCent, double molWeight){ + return perCent*10.0D/molWeight; + } + + // Converts Celsius to Kelvin + public static double celsiusToKelvin(double cels){ + return cels-Fmath.T_ABS; + } + + // Converts Kelvin to Celsius + public static double kelvinToCelsius(double kelv){ + return kelv+Fmath.T_ABS; + } + + // Converts Celsius to Fahrenheit + public static double celsiusToFahren(double cels){ + return cels*(9.0/5.0)+32.0; + } + + // Converts Fahrenheit to Celsius + public static double fahrenToCelsius(double fahr){ + return (fahr-32.0)*5.0/9.0; + } + + // Converts calories to Joules + public static double calorieToJoule(double cal){ + return cal*4.1868; + } + + // Converts Joules to calories + public static double jouleToCalorie(double joule){ + return joule*0.23884; + } + + // Converts grams to ounces + public static double gramToOunce(double gm){ + return gm/28.3459; + } + + // Converts ounces to grams + public static double ounceToGram(double oz){ + return oz*28.3459; + } + + // Converts kilograms to pounds + public static double kgToPound(double kg){ + return kg/0.4536; + } + + // Converts pounds to kilograms + public static double poundToKg(double pds){ + return pds*0.4536; + } + + // Converts kilograms to tons + public static double kgToTon(double kg){ + return kg/1016.05; + } + + // Converts tons to kilograms + public static double tonToKg(double tons){ + return tons*1016.05; + } + + // Converts millimetres to inches + public static double millimetreToInch(double mm){ + return mm/25.4; + } + + // Converts inches to millimetres + public static double inchToMillimetre(double in){ + return in*25.4; + } + + // Converts feet to metres + public static double footToMetre(double ft){ + return ft*0.3048; + } + + // Converts metres to feet + public static double metreToFoot(double metre){ + return metre/0.3048; + } + + // Converts yards to metres + public static double yardToMetre(double yd){ + return yd*0.9144; + } + + // Converts metres to yards + public static double metreToYard(double metre){ + return metre/0.9144; + } + + // Converts miles to kilometres + public static double mileToKm(double mile){ + return mile*1.6093; + } + + // Converts kilometres to miles + public static double kmToMile(double km){ + return km/1.6093; + } + + // Converts UK gallons to litres + public static double gallonToLitre(double gall){ + return gall*4.546; + } + + // Converts litres to UK gallons + public static double litreToGallon(double litre){ + return litre/4.546; + } + + // Converts UK quarts to litres + public static double quartToLitre(double quart){ + return quart*1.137; + } + + // Converts litres to UK quarts + public static double litreToQuart(double litre){ + return litre/1.137; + } + + // Converts UK pints to litres + public static double pintToLitre(double pint){ + return pint*0.568; + } + + // Converts litres to UK pints + public static double litreToPint(double litre){ + return litre/0.568; + } + + // Converts UK gallons per mile to litres per kilometre + public static double gallonPerMileToLitrePerKm(double gallPmile){ + return gallPmile*2.825; + } + + // Converts litres per kilometre to UK gallons per mile + public static double litrePerKmToGallonPerMile(double litrePkm){ + return litrePkm/2.825; + } + + // Converts miles per UK gallons to kilometres per litre + public static double milePerGallonToKmPerLitre(double milePgall){ + return milePgall*0.354; + } + + // Converts kilometres per litre to miles per UK gallons + public static double kmPerLitreToMilePerGallon(double kmPlitre){ + return kmPlitre/0.354; + } + + // Converts UK fluid ounce to American fluid ounce + public static double fluidOunceUKtoUS(double flOzUK){ + return flOzUK*0.961; + } + + // Converts American fluid ounce to UK fluid ounce + public static double fluidOunceUStoUK(double flOzUS){ + return flOzUS*1.041; + } + + // Converts UK pint to American liquid pint + public static double pintUKtoUS(double pintUK){ + return pintUK*1.201; + } + + // Converts American liquid pint to UK pint + public static double pintUStoUK(double pintUS){ + return pintUS*0.833; + } + + // Converts UK quart to American liquid quart + public static double quartUKtoUS(double quartUK){ + return quartUK*1.201; + } + + // Converts American liquid quart to UK quart + public static double quartUStoUK(double quartUS){ + return quartUS*0.833; + } + + // Converts UK gallon to American gallon + public static double gallonUKtoUS(double gallonUK){ + return gallonUK*1.201; + } + + // Converts American gallon to UK gallon + public static double gallonUStoUK(double gallonUS){ + return gallonUS*0.833; + } + + // Converts UK pint to American cup + public static double pintUKtoCupUS(double pintUK){ + return pintUK/0.417; + } + + // Converts American cup to UK pint + public static double cupUStoPintUK(double cupUS){ + return cupUS*0.417; + } + + // Calculates body mass index (BMI) from height (m) and weight (kg) + public static double calcBMImetric(double height, double weight){ + return weight/(height*height); + } + + // Calculates body mass index (BMI) from height (ft) and weight (lbs) + public static double calcBMIimperial(double height, double weight){ + height = Fmath.footToMetre(height); + weight = Fmath.poundToKg(weight); + return weight/(height*height); + } + + // Calculates weight (kg) to give a specified BMI for a given height (m) + public static double calcWeightFromBMImetric(double bmi, double height){ + return bmi*height*height; + } + + // Calculates weight (lbs) to give a specified BMI for a given height (ft) + public static double calcWeightFromBMIimperial(double bmi, double height){ + height = Fmath.footToMetre(height); + double weight = bmi*height*height; + weight = Fmath.kgToPound(weight); + return weight; + } + + // Returns milliseconds since 0 hours 0 minutes 0 seconds on 1 Jan 1970 + public static long dateToJavaMilliSecondsUK(int year, int month, int day, String dayOfTheWeek, int hour, int min, int sec, int millisec){ + + TimeAndDate tad = new TimeAndDate(); + long ms = tad.dateToJavaMilliSecondsUK(year, month, day, dayOfTheWeek, hour, min, sec, millisec); + + return ms; + } + +} diff --git a/src/main/java/flanagan/math/Ffunct.java b/src/main/java/flanagan/math/Ffunct.java new file mode 100644 index 0000000000000000000000000000000000000000..c516f0297aa084a7dda56f99df87b245a052a6a0 --- /dev/null +++ b/src/main/java/flanagan/math/Ffunct.java @@ -0,0 +1,19 @@ +package flanagan.math; + +import flanagan.analysis.Stat; +import flanagan.roots.RealRootFunction; + +// Class to evaluate the F-distribution function +public class Ffunct implements RealRootFunction { + + public double cfd = 0.0D; + public int nu1 = 0; + public int nu2 = 0; + + public double function(double x){ + + double y = cfd - (1.0D - Stat.fCompCDF(x, nu1, nu2)); + + return y; + } +} diff --git a/src/main/java/flanagan/math/Fmath.java b/src/main/java/flanagan/math/Fmath.java new file mode 100755 index 0000000000000000000000000000000000000000..f6da1e8fde605752e9dcb6c122d32f893bf292a3 --- /dev/null +++ b/src/main/java/flanagan/math/Fmath.java @@ -0,0 +1,3943 @@ +/* +* Class Fmath +* +* USAGE: Mathematical class that supplements java.lang.Math and contains: +* the main physical constants +* trigonemetric functions absent from java.lang.Math +* some useful additional mathematical functions +* some conversion functions +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: June 2002 +* AMENDED: 6 January 2006, 12 April 2006, 5 May 2006, 28 July 2006, 27 December 2006, +* 29 March 2007, 29 April 2007, 2,9,15 & 26 June 2007, 20 October 2007, 4-6 December 2007 +* 27 February 2008, 25 April 2008, 26 April 2008, 13 May 2008, 25/26 May 2008, 3-7 July 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* http://www.ee.ucl.ac.uk/~mflanaga/java/Fmath.html +* +* Copyright (c) 2002 - 2008 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.math; + +import java.util.ArrayList; +import java.util.Vector; +import java.io.IOException; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectInputStream; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; + +public class Fmath{ + + // PHYSICAL CONSTANTS + + public static final double N_AVAGADRO = 6.0221419947e23; /* mol^-1 */ + public static final double K_BOLTZMANN = 1.380650324e-23; /* J K^-1 */ + public static final double H_PLANCK = 6.6260687652e-34; /* J s */ + public static final double H_PLANCK_RED = H_PLANCK/(2*Math.PI); /* J s */ + public static final double C_LIGHT = 2.99792458e8; /* m s^-1 */ + public static final double R_GAS = 8.31447215; /* J K^-1 mol^-1 */ + public static final double F_FARADAY = 9.6485341539e4; /* C mol^-1 */ + public static final double T_ABS = -273.15; /* Celsius */ + public static final double Q_ELECTRON = -1.60217646263e-19; /* C */ + public static final double M_ELECTRON = 9.1093818872e-31; /* kg */ + public static final double M_PROTON = 1.6726215813e-27; /* kg */ + public static final double M_NEUTRON = 1.6749271613e-27; /* kg */ + public static final double EPSILON_0 = 8.854187817e-12; /* F m^-1 */ + public static final double MU_0 = Math.PI*4e-7; /* H m^-1 (N A^-2) */ + + // MATHEMATICAL CONSTANTS + public static final double EULER_CONSTANT_GAMMA = 0.5772156649015627; + public static final double PI = Math.PI; /* 3.141592653589793D */ + public static final double E = Math.E; /* 2.718281828459045D */ + + // HashMap for 'arithmetic integer' recognition nmethod + private static final Map<Object,Object> integers = new HashMap<Object,Object>(); + static{ + integers.put(Integer.class, BigDecimal.valueOf(Integer.MAX_VALUE)); + integers.put(Long.class, BigDecimal.valueOf(Long.MAX_VALUE)); + integers.put(Byte.class, BigDecimal.valueOf(Byte.MAX_VALUE)); + integers.put(Short.class, BigDecimal.valueOf(Short.MAX_VALUE)); + integers.put(BigInteger.class, BigDecimal.valueOf(-1)); + } + + // METHODS + + // LOGARITHMS + // Log to base 10 of a double number + public static double log10(double a){ + return Math.log(a)/Math.log(10.0D); + } + + // Log to base 10 of a float number + public static float log10(float a){ + return (float) (Math.log((double)a)/Math.log(10.0D)); + } + + // Base 10 antilog of a double + public static double antilog10(double x){ + return Math.pow(10.0D, x); + } + + // Base 10 antilog of a float + public static float antilog10(float x){ + return (float)Math.pow(10.0D, (double)x); + } + + // Log to base e of a double number + public static double log(double a){ + return Math.log(a); + } + + // Log to base e of a float number + public static float log(float a){ + return (float)Math.log((double)a); + } + + // Base e antilog of a double + public static double antilog(double x){ + return Math.exp(x); + } + + // Base e antilog of a float + public static float antilog(float x){ + return (float)Math.exp((double)x); + } + + // Log to base 2 of a double number + public static double log2(double a){ + return Math.log(a)/Math.log(2.0D); + } + + // Log to base 2 of a float number + public static float log2(float a){ + return (float) (Math.log((double)a)/Math.log(2.0D)); + } + + // Base 2 antilog of a double + public static double antilog2(double x){ + return Math.pow(2.0D, x); + } + + // Base 2 antilog of a float + public static float antilog2(float x){ + return (float)Math.pow(2.0D, (double)x); + } + + // Log to base b of a double number and double base + public static double log10(double a, double b){ + return Math.log(a)/Math.log(b); + } + + // Log to base b of a double number and int base + public static double log10(double a, int b){ + return Math.log(a)/Math.log((double)b); + } + + // Log to base b of a float number and flaot base + public static float log10(float a, float b){ + return (float) (Math.log((double)a)/Math.log((double)b)); + } + + // Log to base b of a float number and int base + public static float log10(float a, int b){ + return (float) (Math.log((double)a)/Math.log((double)b)); + } + + // SQUARES + // Square of a double number + public static double square(double a){ + return a*a; + } + + // Square of a float number + public static float square(float a){ + return a*a; + } + + // Square of a BigDecimal number + public static BigDecimal square(BigDecimal a){ + return a.multiply(a); + } + + // Square of an int number + public static int square(int a){ + return a*a; + } + + // Square of a long number + public static long square(long a){ + return a*a; + } + + // Square of a BigInteger number + public static BigInteger square(BigInteger a){ + return a.multiply(a); + } + + // FACTORIALS + // factorial of n + // argument and return are integer, therefore limited to 0<=n<=12 + // see below for long and double arguments + public static int factorial(int n){ + if(n<0)throw new IllegalArgumentException("n must be a positive integer"); + if(n>12)throw new IllegalArgumentException("n must less than 13 to avoid integer overflow\nTry long or double argument"); + int f = 1; + for(int i=2; i<=n; i++)f*=i; + return f; + } + + // factorial of n + // argument and return are long, therefore limited to 0<=n<=20 + // see below for double argument + public static long factorial(long n){ + if(n<0)throw new IllegalArgumentException("n must be a positive integer"); + if(n>20)throw new IllegalArgumentException("n must less than 21 to avoid long integer overflow\nTry double argument"); + long f = 1; + long iCount = 2L; + while(iCount<=n){ + f*=iCount; + iCount += 1L; + } + return f; + } + + // factorial of n + // Argument is of type BigInteger + public static BigInteger factorial(BigInteger n){ + if(n.compareTo(BigInteger.ZERO)==-1)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?"); + BigInteger one = BigInteger.ONE; + BigInteger f = one; + BigInteger iCount = new BigInteger("2"); + while(iCount.compareTo(n)!=1){ + f = f.multiply(iCount); + iCount = iCount.add(one); + } + one = null; + iCount = null; + return f; + } + + // factorial of n + // Argument is of type double but must be, numerically, an integer + // factorial returned as double but is, numerically, should be an integer + // numerical rounding may makes this an approximation after n = 21 + public static double factorial(double n){ + if(n<0.0 || (n-Math.floor(n))!=0)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?"); + double f = 1.0D; + double iCount = 2.0D; + while(iCount<=n){ + f*=iCount; + iCount += 1.0D; + } + return f; + } + + // factorial of n + // Argument is of type BigDecimal but must be, numerically, an integer + public static BigDecimal factorial(BigDecimal n){ + if(n.compareTo(BigDecimal.ZERO)==-1 || !Fmath.isInteger(n))throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?"); + BigDecimal one = BigDecimal.ONE; + BigDecimal f = one; + BigDecimal iCount = new BigDecimal(2.0D); + while(iCount.compareTo(n)!=1){ + f = f.multiply(iCount); + iCount = iCount.add(one); + } + one = null; + iCount = null; + return f; + } + + + + // log to base e of the factorial of n + // log[e](factorial) returned as double + // numerical rounding may makes this an approximation + public static double logFactorial(int n){ + if(n<0)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?"); + double f = 0.0D; + for(int i=2; i<=n; i++)f+=Math.log(i); + return f; + } + + // log to base e of the factorial of n + // Argument is of type double but must be, numerically, an integer + // log[e](factorial) returned as double + // numerical rounding may makes this an approximation + public static double logFactorial(long n){ + if(n<0L)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?"); + double f = 0.0D; + long iCount = 2L; + while(iCount<=n){ + f+=Math.log(iCount); + iCount += 1L; + } + return f; + } + + // log to base e of the factorial of n + // Argument is of type double but must be, numerically, an integer + // log[e](factorial) returned as double + // numerical rounding may makes this an approximation + public static double logFactorial(double n){ + if(n<0 || (n-Math.floor(n))!=0)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?"); + double f = 0.0D; + double iCount = 2.0D; + while(iCount<=n){ + f+=Math.log(iCount); + iCount += 1.0D; + } + return f; + } + + + // SIGN + /* returns -1 if x < 0 else returns 1 */ + // double version + public static double sign(double x){ + if (x<0.0){ + return -1.0; + } + else{ + return 1.0; + } + } + + /* returns -1 if x < 0 else returns 1 */ + // float version + public static float sign(float x){ + if (x<0.0F){ + return -1.0F; + } + else{ + return 1.0F; + } + } + + /* returns -1 if x < 0 else returns 1 */ + // int version + public static int sign(int x){ + if (x<0){ + return -1; + } + else{ + return 1; + } + } + + /* returns -1 if x < 0 else returns 1 */ + // long version + public static long sign(long x){ + if (x<0){ + return -1; + } + else{ + return 1; + } + } + + // ADDITIONAL TRIGONOMETRIC FUNCTIONS + + // Returns the length of the hypotenuse of a and b + // i.e. sqrt(a*a+b*b) [without unecessary overflow or underflow] + // double version + public static double hypot(double aa, double bb){ + double amod=Math.abs(aa); + double bmod=Math.abs(bb); + double cc = 0.0D, ratio = 0.0D; + if(amod==0.0){ + cc=bmod; + } + else{ + if(bmod==0.0){ + cc=amod; + } + else{ + if(amod>=bmod){ + ratio=bmod/amod; + cc=amod*Math.sqrt(1.0 + ratio*ratio); + } + else{ + ratio=amod/bmod; + cc=bmod*Math.sqrt(1.0 + ratio*ratio); + } + } + } + return cc; + } + + // Returns the length of the hypotenuse of a and b + // i.e. sqrt(a*a+b*b) [without unecessary overflow or underflow] + // float version + public static float hypot(float aa, float bb){ + return (float) hypot((double) aa, (double) bb); + } + + // Angle (in radians) subtended at coordinate C + // given x, y coordinates of all apices, A, B and C, of a triangle + public static double angle(double xAtA, double yAtA, double xAtB, double yAtB, double xAtC, double yAtC){ + + double ccos = Fmath.cos(xAtA, yAtA, xAtB, yAtB, xAtC, yAtC); + return Math.acos(ccos); + } + + // Angle (in radians) between sides sideA and sideB given all side lengths of a triangle + public static double angle(double sideAC, double sideBC, double sideAB){ + + double ccos = Fmath.cos(sideAC, sideBC, sideAB); + return Math.acos(ccos); + } + + // Sine of angle subtended at coordinate C + // given x, y coordinates of all apices, A, B and C, of a triangle + public static double sin(double xAtA, double yAtA, double xAtB, double yAtB, double xAtC, double yAtC){ + double angle = Fmath.angle(xAtA, yAtA, xAtB, yAtB, xAtC, yAtC); + return Math.sin(angle); + } + + // Sine of angle between sides sideA and sideB given all side lengths of a triangle + public static double sin(double sideAC, double sideBC, double sideAB){ + double angle = Fmath.angle(sideAC, sideBC, sideAB); + return Math.sin(angle); + } + + // Sine given angle in radians + // for completion - returns Math.sin(arg) + public static double sin(double arg){ + return Math.sin(arg); + } + + // Inverse sine + // Fmath.asin Checks limits - Java Math.asin returns NaN if without limits + public static double asin(double a){ + if(a<-1.0D && a>1.0D) throw new IllegalArgumentException("Fmath.asin argument (" + a + ") must be >= -1.0 and <= 1.0"); + return Math.asin(a); + } + + // Cosine of angle subtended at coordinate C + // given x, y coordinates of all apices, A, B and C, of a triangle + public static double cos(double xAtA, double yAtA, double xAtB, double yAtB, double xAtC, double yAtC){ + double sideAC = Fmath.hypot(xAtA - xAtC, yAtA - yAtC); + double sideBC = Fmath.hypot(xAtB - xAtC, yAtB - yAtC); + double sideAB = Fmath.hypot(xAtA - xAtB, yAtA - yAtB); + return Fmath.cos(sideAC, sideBC, sideAB); + } + + // Cosine of angle between sides sideA and sideB given all side lengths of a triangle + public static double cos(double sideAC, double sideBC, double sideAB){ + return 0.5D*(sideAC/sideBC + sideBC/sideAC - (sideAB/sideAC)*(sideAB/sideBC)); + } + + // Cosine given angle in radians + // for completion - returns Java Math.cos(arg) + public static double cos(double arg){ + return Math.cos(arg); + } + + // Inverse cosine + // Fmath.asin Checks limits - Java Math.asin returns NaN if without limits + public static double acos(double a){ + if(a<-1.0D || a>1.0D) throw new IllegalArgumentException("Fmath.acos argument (" + a + ") must be >= -1.0 and <= 1.0"); + return Math.acos(a); + } + + // Tangent of angle subtended at coordinate C + // given x, y coordinates of all apices, A, B and C, of a triangle + public static double tan(double xAtA, double yAtA, double xAtB, double yAtB, double xAtC, double yAtC){ + double angle = Fmath.angle(xAtA, yAtA, xAtB, yAtB, xAtC, yAtC); + return Math.tan(angle); + } + + // Tangent of angle between sides sideA and sideB given all side lengths of a triangle + public static double tan(double sideAC, double sideBC, double sideAB){ + double angle = Fmath.angle(sideAC, sideBC, sideAB); + return Math.tan(angle); + } + + // Tangent given angle in radians + // for completion - returns Math.tan(arg) + public static double tan(double arg){ + return Math.tan(arg); + } + + // Inverse tangent + // for completion - returns Math.atan(arg) + public static double atan(double a){ + return Math.atan(a); + } + + // Inverse tangent - ratio numerator and denominator provided + // for completion - returns Math.atan2(arg) + public static double atan2(double a, double b){ + return Math.atan2(a, b); + } + + // Cotangent + public static double cot(double a){ + return 1.0D/Math.tan(a); + } + + // Inverse cotangent + public static double acot(double a){ + return Math.atan(1.0D/a); + } + + // Inverse cotangent - ratio numerator and denominator provided + public static double acot2(double a, double b){ + return Math.atan2(b, a); + } + + // Secant + public static double sec(double a){ + return 1.0/Math.cos(a); + } + + // Inverse secant + public static double asec(double a){ + if(a<1.0D && a>-1.0D) throw new IllegalArgumentException("asec argument (" + a + ") must be >= 1 or <= -1"); + return Math.acos(1.0/a); + } + + // Cosecant + public static double csc(double a){ + return 1.0D/Math.sin(a); + } + + // Inverse cosecant + public static double acsc(double a){ + if(a<1.0D && a>-1.0D) throw new IllegalArgumentException("acsc argument (" + a + ") must be >= 1 or <= -1"); + return Math.asin(1.0/a); + } + + // Exsecant + public static double exsec(double a){ + return (1.0/Math.cos(a)-1.0D); + } + + // Inverse exsecant + public static double aexsec(double a){ + if(a<0.0D && a>-2.0D) throw new IllegalArgumentException("aexsec argument (" + a + ") must be >= 0.0 and <= -2"); + return Math.asin(1.0D/(1.0D + a)); + } + + // Versine + public static double vers(double a){ + return (1.0D - Math.cos(a)); + } + + // Inverse versine + public static double avers(double a){ + if(a<0.0D && a>2.0D) throw new IllegalArgumentException("avers argument (" + a + ") must be <= 2 and >= 0"); + return Math.acos(1.0D - a); + } + + // Coversine + public static double covers(double a){ + return (1.0D - Math.sin(a)); + } + + // Inverse coversine + public static double acovers(double a){ + if(a<0.0D && a>2.0D) throw new IllegalArgumentException("acovers argument (" + a + ") must be <= 2 and >= 0"); + return Math.asin(1.0D - a); + } + + // Haversine + public static double hav(double a){ + return 0.5D*Fmath.vers(a); + } + + // Inverse haversine + public static double ahav(double a){ + if(a<0.0D && a>1.0D) throw new IllegalArgumentException("ahav argument (" + a + ") must be >= 0 and <= 1"); + return Fmath.acos(1.0D - 2.0D*a); + } + + // Unnormalised sinc (unnormalised sine cardinal) sin(x)/x + public static double sinc(double a){ + if(Math.abs(a)<1e-40){ + return 1.0D; + } + else{ + return Math.sin(a)/a; + } + } + + // Normalised sinc (normalised sine cardinal) sin(pi.x)/(pi.x) + public static double nsinc(double a){ + if(Math.abs(a)<1e-40){ + return 1.0D; + } + else{ + return Math.sin(Math.PI*a)/(Math.PI*a); + } + } + + //Hyperbolic sine of a double number + public static double sinh(double a){ + return 0.5D*(Math.exp(a)-Math.exp(-a)); + } + + // Inverse hyperbolic sine of a double number + public static double asinh(double a){ + double sgn = 1.0D; + if(a<0.0D){ + sgn = -1.0D; + a = -a; + } + return sgn*Math.log(a+Math.sqrt(a*a+1.0D)); + } + + //Hyperbolic cosine of a double number + public static double cosh(double a){ + return 0.5D*(Math.exp(a)+Math.exp(-a)); + } + + // Inverse hyperbolic cosine of a double number + public static double acosh(double a){ + if(a<1.0D) throw new IllegalArgumentException("acosh real number argument (" + a + ") must be >= 1"); + return Math.log(a+Math.sqrt(a*a-1.0D)); + } + + //Hyperbolic tangent of a double number + public static double tanh(double a){ + return sinh(a)/cosh(a); + } + + // Inverse hyperbolic tangent of a double number + public static double atanh(double a){ + double sgn = 1.0D; + if(a<0.0D){ + sgn = -1.0D; + a = -a; + } + if(a>1.0D) throw new IllegalArgumentException("atanh real number argument (" + sgn*a + ") must be >= -1 and <= 1"); + return 0.5D*sgn*(Math.log(1.0D + a)-Math.log(1.0D - a)); + } + + //Hyperbolic cotangent of a double number + public static double coth(double a){ + return 1.0D/tanh(a); + } + + // Inverse hyperbolic cotangent of a double number + public static double acoth(double a){ + double sgn = 1.0D; + if(a<0.0D){ + sgn = -1.0D; + a = -a; + } + if(a<1.0D) throw new IllegalArgumentException("acoth real number argument (" + sgn*a + ") must be <= -1 or >= 1"); + return 0.5D*sgn*(Math.log(1.0D + a)-Math.log(a - 1.0D)); + } + + //Hyperbolic secant of a double number + public static double sech(double a){ + return 1.0D/cosh(a); + } + + // Inverse hyperbolic secant of a double number + public static double asech(double a){ + if(a>1.0D || a<0.0D) throw new IllegalArgumentException("asech real number argument (" + a + ") must be >= 0 and <= 1"); + return 0.5D*(Math.log(1.0D/a + Math.sqrt(1.0D/(a*a) - 1.0D))); + } + + //Hyperbolic cosecant of a double number + public static double csch(double a){ + return 1.0D/sinh(a); + } + + // Inverse hyperbolic cosecant of a double number + public static double acsch(double a){ + double sgn = 1.0D; + if(a<0.0D){ + sgn = -1.0D; + a = -a; + } + return 0.5D*sgn*(Math.log(1.0/a + Math.sqrt(1.0D/(a*a) + 1.0D))); + } + + // MANTISSA ROUNDING (TRUNCATING) + // returns a value of xDouble truncated to trunc decimal places + public static double truncate(double xDouble, int trunc){ + double xTruncated = xDouble; + if(!Fmath.isNaN(xDouble)){ + if(!Fmath.isPlusInfinity(xDouble)){ + if(!Fmath.isMinusInfinity(xDouble)){ + if(xDouble!=0.0D){ + String xString = ((new Double(xDouble)).toString()).trim(); + xTruncated = Double.parseDouble(truncateProcedure(xString, trunc)); + } + } + } + } + return xTruncated; + } + + // returns a value of xFloat truncated to trunc decimal places + public static float truncate(float xFloat, int trunc){ + float xTruncated = xFloat; + if(!Fmath.isNaN(xFloat)){ + if(!Fmath.isPlusInfinity(xFloat)){ + if(!Fmath.isMinusInfinity(xFloat)){ + if(xFloat!=0.0D){ + String xString = ((new Float(xFloat)).toString()).trim(); + xTruncated = Float.parseFloat(truncateProcedure(xString, trunc)); + } + } + } + } + return xTruncated; + } + + // private method for truncating a float or double expressed as a String + private static String truncateProcedure(String xValue, int trunc){ + + String xTruncated = xValue; + String xWorking = xValue; + String exponent = " "; + String first = "+"; + int expPos = xValue.indexOf('E'); + int dotPos = xValue.indexOf('.'); + int minPos = xValue.indexOf('-'); + + if(minPos!=-1){ + if(minPos==0){ + xWorking = xWorking.substring(1); + first = "-"; + dotPos--; + expPos--; + } + } + if(expPos>-1){ + exponent = xWorking.substring(expPos); + xWorking = xWorking.substring(0,expPos); + } + String xPreDot = null; + String xPostDot = "0"; + String xDiscarded = null; + String tempString = null; + double tempDouble = 0.0D; + if(dotPos>-1){ + xPreDot = xWorking.substring(0,dotPos); + xPostDot = xWorking.substring(dotPos+1); + int xLength = xPostDot.length(); + if(trunc<xLength){ + xDiscarded = xPostDot.substring(trunc); + tempString = xDiscarded.substring(0,1) + "."; + if(xDiscarded.length()>1){ + tempString += xDiscarded.substring(1); + } + else{ + tempString += "0"; + } + tempDouble = Math.round(Double.parseDouble(tempString)); + + if(trunc>0){ + if(tempDouble>=5.0){ + int[] xArray = new int[trunc+1]; + xArray[0] = 0; + for(int i=0; i<trunc; i++){ + xArray[i+1] = Integer.parseInt(xPostDot.substring(i,i+1)); + } + boolean test = true; + int iCounter = trunc; + while(test){ + xArray[iCounter] += 1; + if(iCounter>0){ + if(xArray[iCounter]<10){ + test = false; + } + else{ + xArray[iCounter]=0; + iCounter--; + } + } + else{ + test = false; + } + } + int preInt = Integer.parseInt(xPreDot); + preInt += xArray[0]; + xPreDot = (new Integer(preInt)).toString(); + tempString = ""; + for(int i=1; i<=trunc; i++){ + tempString += (new Integer(xArray[i])).toString(); + } + xPostDot = tempString; + } + else{ + xPostDot = xPostDot.substring(0, trunc); + } + } + else{ + if(tempDouble>=5.0){ + int preInt = Integer.parseInt(xPreDot); + preInt++; + xPreDot = (new Integer(preInt)).toString(); + } + xPostDot = "0"; + } + } + xTruncated = first + xPreDot.trim() + "." + xPostDot.trim() + exponent; + } + return xTruncated.trim(); + } + + // Returns true if x is infinite, i.e. is equal to either plus or minus infinity + // x is double + public static boolean isInfinity(double x){ + boolean test=false; + if(x==Double.POSITIVE_INFINITY || x==Double.NEGATIVE_INFINITY)test=true; + return test; + } + + // Returns true if x is infinite, i.e. is equal to either plus or minus infinity + // x is float + public static boolean isInfinity(float x){ + boolean test=false; + if(x==Float.POSITIVE_INFINITY || x==Float.NEGATIVE_INFINITY)test=true; + return test; + } + + // Returns true if x is plus infinity + // x is double + public static boolean isPlusInfinity(double x){ + boolean test=false; + if(x==Double.POSITIVE_INFINITY)test=true; + return test; + } + + // Returns true if x is plus infinity + // x is float + public static boolean isPlusInfinity(float x){ + boolean test=false; + if(x==Float.POSITIVE_INFINITY)test=true; + return test; + } + + // Returns true if x is minus infinity + // x is double + public static boolean isMinusInfinity(double x){ + boolean test=false; + if(x==Double.NEGATIVE_INFINITY)test=true; + return test; + } + + // Returns true if x is minus infinity + // x is float + public static boolean isMinusInfinity(float x){ + boolean test=false; + if(x==Float.NEGATIVE_INFINITY)test=true; + return test; + } + + + // Returns true if x is 'Not a Number' (NaN) + // x is double + public static boolean isNaN(double x){ + boolean test=false; + if(x!=x)test=true; + return test; + } + + // Returns true if x is 'Not a Number' (NaN) + // x is float + public static boolean isNaN(float x){ + boolean test=false; + if(x!=x)test=true; + return test; + } + + // Returns true if x equals y + // x and y are double + // x may be float within range, PLUS_INFINITY, NEGATIVE_INFINITY, or NaN + // NB!! This method treats two NaNs as equal + public static boolean isEqual(double x, double y){ + boolean test=false; + if(Fmath.isNaN(x)){ + if(Fmath.isNaN(y))test=true; + } + else{ + if(Fmath.isPlusInfinity(x)){ + if(Fmath.isPlusInfinity(y))test=true; + } + else{ + if(Fmath.isMinusInfinity(x)){ + if(Fmath.isMinusInfinity(y))test=true; + } + else{ + if(x==y)test=true; + } + } + } + return test; + } + + // Returns true if x equals y + // x and y are float + // x may be float within range, PLUS_INFINITY, NEGATIVE_INFINITY, or NaN + // NB!! This method treats two NaNs as equal + public static boolean isEqual(float x, float y){ + boolean test=false; + if(Fmath.isNaN(x)){ + if(Fmath.isNaN(y))test=true; + } + else{ + if(Fmath.isPlusInfinity(x)){ + if(Fmath.isPlusInfinity(y))test=true; + } + else{ + if(Fmath.isMinusInfinity(x)){ + if(Fmath.isMinusInfinity(y))test=true; + } + else{ + if(x==y)test=true; + } + } + } + return test; + } + + // Returns true if x equals y + // x and y are int + public static boolean isEqual(int x, int y){ + boolean test=false; + if(x==y)test=true; + return test; + } + + // Returns true if x equals y + // x and y are char + public static boolean isEqual(char x, char y){ + boolean test=false; + if(x==y)test=true; + return test; + } + + // Returns true if x equals y + // x and y are Strings + public static boolean isEqual(String x, String y){ + boolean test=false; + if(x.equals(y))test=true; + return test; + } + + // IS EQUAL WITHIN LIMITS + // Returns true if x equals y within limits plus or minus limit + // x and y are double + public static boolean isEqualWithinLimits(double x, double y, double limit){ + boolean test=false; + if(Math.abs(x-y)<=Math.abs(limit))test=true; + return test; + } + + // Returns true if x equals y within limits plus or minus limit + // x and y are float + public static boolean isEqualWithinLimits(float x, float y, float limit){ + boolean test=false; + if(Math.abs(x-y)<=Math.abs(limit))test=true; + return test; + } + + // Returns true if x equals y within limits plus or minus limit + // x and y are long + public static boolean isEqualWithinLimits(long x, long y, long limit){ + boolean test=false; + if(Math.abs(x-y)<=Math.abs(limit))test=true; + return test; + } + + // Returns true if x equals y within limits plus or minus limit + // x and y are int + public static boolean isEqualWithinLimits(int x, int y, int limit){ + boolean test=false; + if(Math.abs(x-y)<=Math.abs(limit))test=true; + return test; + } + + // Returns true if x equals y within limits plus or minus limit + // x and y are BigDecimal + public static boolean isEqualWithinLimits(BigDecimal x, BigDecimal y, BigDecimal limit){ + boolean test=false; + if(((x.subtract(y)).abs()).compareTo(limit.abs())<=0)test = true; + return test; + } + + // Returns true if x equals y within limits plus or minus limit + // x and y are BigInteger + public static boolean isEqualWithinLimits(BigInteger x, BigInteger y, BigInteger limit){ + boolean test=false; + if(((x.subtract(y)).abs()).compareTo(limit.abs())<=0)test = true; + return test; + } + + + // IS EQUAL WITHIN A PERCENTAGE + // Returns true if x equals y within a percentage of the mean + // x and y are double + public static boolean isEqualWithinPerCent(double x, double y, double perCent){ + boolean test=false; + double limit = Math.abs((x+y)*perCent/200.0D); + if(Math.abs(x-y)<=limit)test=true; + return test; + } + + // Returns true if x equals y within a percentage of the mean + // x and y are float + public static boolean isEqualWithinPerCent(float x, float y, float perCent){ + boolean test=false; + double limit = Math.abs((x+y)*perCent/200.0F); + if(Math.abs(x-y)<=limit)test=true; + return test; + } + + // Returns true if x equals y within a percentage of the mean + // x and y are long, percentage provided as double + public static boolean isEqualWithinPerCent(long x, long y, double perCent){ + boolean test=false; + double limit = Math.abs((x+y)*perCent/200.0D); + if(Math.abs(x-y)<=limit)test=true; + return test; + } + + // Returns true if x equals y within a percentage of the mean + // x and y are long, percentage provided as int + public static boolean isEqualWithinPerCent(long x, long y, long perCent){ + boolean test=false; + double limit = Math.abs((double)(x+y)*(double)perCent/200.0D); + if(Math.abs(x-y)<=limit)test=true; + return test; + } + + // Returns true if x equals y within a percentage of the mean + // x and y are int, percentage provided as double + public static boolean isEqualWithinPerCent(int x, int y, double perCent){ + boolean test=false; + double limit = Math.abs((double)(x+y)*perCent/200.0D); + if(Math.abs(x-y)<=limit)test=true; + return test; + } + + // Returns true if x equals y within a percentage of the mean + // x and y are int, percentage provided as int + public static boolean isEqualWithinPerCent(int x, int y, int perCent){ + boolean test=false; + double limit = Math.abs((double)(x+y)*(double)perCent/200.0D); + if(Math.abs(x-y)<=limit)test=true; + return test; + } + + // Returns true if x equals y within a percentage of the mean + // x and y are BigDecimal + public static boolean isEqualWithinPerCent(BigDecimal x, BigDecimal y, BigDecimal perCent){ + boolean test=false; + BigDecimal limit = (x.add(y)).multiply(perCent).multiply(new BigDecimal("0.005")); + if(((x.subtract(y)).abs()).compareTo(limit.abs())<=0)test = true; + limit = null; + return test; + } + + // Returns true if x equals y within a percentage of the mean + // x and y are BigDInteger, percentage provided as BigDecimal + public static boolean isEqualWithinPerCent(BigInteger x, BigInteger y, BigDecimal perCent){ + boolean test=false; + BigDecimal xx = new BigDecimal(x); + BigDecimal yy = new BigDecimal(y); + BigDecimal limit = (xx.add(yy)).multiply(perCent).multiply(new BigDecimal("0.005")); + if(((xx.subtract(yy)).abs()).compareTo(limit.abs())<=0)test = true; + limit = null; + xx = null; + yy = null; + return test; + } + + // Returns true if x equals y within a percentage of the mean + // x and y are BigDInteger, percentage provided as BigInteger + public static boolean isEqualWithinPerCent(BigInteger x, BigInteger y, BigInteger perCent){ + boolean test=false; + BigDecimal xx = new BigDecimal(x); + BigDecimal yy = new BigDecimal(y); + BigDecimal pc = new BigDecimal(perCent); + BigDecimal limit = (xx.add(yy)).multiply(pc).multiply(new BigDecimal("0.005")); + if(((xx.subtract(yy)).abs()).compareTo(limit.abs())<=0)test = true; + limit = null; + xx = null; + yy = null; + pc = null; + return test; + } + + // COMPARISONS + // Returns 0 if x == y + // Returns -1 if x < y + // Returns 1 if x > y + // x and y are double + public static int compare(double x, double y){ + Double X = new Double(x); + Double Y = new Double(y); + return X.compareTo(Y); + } + + // Returns 0 if x == y + // Returns -1 if x < y + // Returns 1 if x > y + // x and y are int + public static int compare(int x, int y){ + Integer X = new Integer(x); + Integer Y = new Integer(y); + return X.compareTo(Y); + } + + // Returns 0 if x == y + // Returns -1 if x < y + // Returns 1 if x > y + // x and y are long + public static int compare(long x, long y){ + Long X = new Long(x); + Long Y = new Long(y); + return X.compareTo(Y); + } + + // Returns 0 if x == y + // Returns -1 if x < y + // Returns 1 if x > y + // x and y are float + public static int compare(float x, float y){ + Float X = new Float(x); + Float Y = new Float(y); + return X.compareTo(Y); + } + + // Returns 0 if x == y + // Returns -1 if x < y + // Returns 1 if x > y + // x and y are short + public static int compare(byte x, byte y){ + Byte X = new Byte(x); + Byte Y = new Byte(y); + return X.compareTo(Y); + } + + // Returns 0 if x == y + // Returns -1 if x < y + // Returns 1 if x > y + // x and y are short + public static int compare(short x, short y){ + Short X = new Short(x); + Short Y = new Short(y); + return X.compareTo(Y); + } + + // IS AN INTEGER + // Returns true if x is, arithmetically, an integer + // Returns false if x is not, arithmetically, an integer + public static boolean isInteger(double x){ + boolean retn = false; + double xfloor = Math.floor(x); + if((x - xfloor)==0.0D) retn = true; + return retn; + } + + // Returns true if all elements in the array x are, arithmetically, integers + // Returns false if any element in the array x is not, arithmetically, an integer + public static boolean isInteger(double[] x){ + boolean retn = true; + boolean test = true; + int ii = 0; + while(test){ + double xfloor = Math.floor(x[ii]); + if((x[ii] - xfloor)!=0.0D){ + retn = false; + test = false; + } + else{ + ii++; + if(ii==x.length)test=false; + } + } + return retn; + } + + // Returns true if x is, arithmetically, an integer + // Returns false if x is not, arithmetically, an integer + public static boolean isInteger(float x){ + boolean ret = false; + float xfloor = (float)Math.floor(x); + if((x - xfloor)==0.0F) ret = true; + return ret; + } + + + // Returns true if all elements in the array x are, arithmetically, integers + // Returns false if any element in the array x is not, arithmetically, an integer + public static boolean isInteger(float[] x){ + boolean retn = true; + boolean test = true; + int ii = 0; + while(test){ + float xfloor = (float)Math.floor(x[ii]); + if((x[ii] - xfloor)!=0.0D){ + retn = false; + test = false; + } + else{ + ii++; + if(ii==x.length)test=false; + } + } + return retn; + } + + public static boolean isInteger (Number numberAsObject){ + boolean test = integers.containsKey(numberAsObject.getClass()); + if(!test){ + if(numberAsObject instanceof Double){ + double dd = numberAsObject.doubleValue(); + test = Fmath.isInteger(dd); + } + if(numberAsObject instanceof Float){ + float dd = numberAsObject.floatValue(); + test = Fmath.isInteger(dd); + } + if(numberAsObject instanceof BigDecimal){ + double dd = numberAsObject.doubleValue(); + test = Fmath.isInteger(dd); + } + } + return test; + } + + public static boolean isInteger (Number[] numberAsObject){ + boolean testall = true; + for(int i=0; i<numberAsObject.length; i++){ + boolean test = integers.containsKey(numberAsObject[i].getClass()); + if(!test){ + if(numberAsObject[i] instanceof Double){ + double dd = numberAsObject[i].doubleValue(); + test = Fmath.isInteger(dd); + if(!test)testall = false; + } + if(numberAsObject[i] instanceof Float){ + float dd = numberAsObject[i].floatValue(); + test = Fmath.isInteger(dd); + if(!test)testall = false; + } + if(numberAsObject[i] instanceof BigDecimal){ + double dd = numberAsObject[i].doubleValue(); + test = Fmath.isInteger(dd); + if(!test)testall = false; + } + } + } + return testall; + } + + // IS EVEN + // Returns true if x is an even number, false if x is an odd number + // x is int + public static boolean isEven(int x){ + boolean test=false; + if(x%2 == 0.0D)test=true; + return test; + } + + // Returns true if x is an even number, false if x is an odd number + // x is float but must hold an integer value + public static boolean isEven(float x){ + double y=Math.floor(x); + if(((double)x - y)!= 0.0D)throw new IllegalArgumentException("the argument is not an integer"); + boolean test=false; + y=Math.floor(x/2.0F); + if(((double)(x/2.0F)-y) == 0.0D)test=true; + return test; + } + + // Returns true if x is an even number, false if x is an odd number + // x is double but must hold an integer value + public static boolean isEven(double x){ + double y=Math.floor(x); + if((x - y)!= 0.0D)throw new IllegalArgumentException("the argument is not an integer"); + boolean test=false; + y=Math.floor(x/2.0F); + if((x/2.0D-y) == 0.0D)test=true; + return test; + } + + // IS ODD + // Returns true if x is an odd number, false if x is an even number + // x is int + public static boolean isOdd(int x){ + boolean test=true; + if(x%2 == 0.0D)test=false; + return test; + } + + // Returns true if x is an odd number, false if x is an even number + // x is float but must hold an integer value + public static boolean isOdd(float x){ + double y=Math.floor(x); + if(((double)x - y)!= 0.0D)throw new IllegalArgumentException("the argument is not an integer"); + boolean test=true; + y=Math.floor(x/2.0F); + if(((double)(x/2.0F)-y) == 0.0D)test=false; + return test; + } + + // Returns true if x is an odd number, false if x is an even number + // x is double but must hold an integer value + public static boolean isOdd(double x){ + double y=Math.floor(x); + if((x - y)!= 0.0D)throw new IllegalArgumentException("the argument is not an integer"); + boolean test=true; + y=Math.floor(x/2.0F); + if((x/2.0D-y) == 0.0D)test=false; + return test; + } + + // LEAP YEAR + // Returns true if year (argument) is a leap year + public static boolean leapYear(int year){ + boolean test = false; + + if(year%4 != 0){ + test = false; + } + else{ + if(year%400 == 0){ + test=true; + } + else{ + if(year%100 == 0){ + test=false; + } + else{ + test=true; + } + } + } + return test; + } + + // COMPUTER TIME + // Returns milliseconds since 0 hours 0 minutes 0 seconds on 1 Jan 1970 + public static long dateToJavaMilliS(int year, int month, int day, int hour, int min, int sec){ + + long[] monthDays = {0L, 31L, 28L, 31L, 30L, 31L, 30L, 31L, 31L, 30L, 31L, 30L, 31L}; + long ms = 0L; + + long yearDiff = 0L; + int yearTest = year-1; + while(yearTest>=1970){ + yearDiff += 365; + if(Fmath.leapYear(yearTest))yearDiff++; + yearTest--; + } + yearDiff *= 24L*60L*60L*1000L; + + long monthDiff = 0L; + int monthTest = month -1; + while(monthTest>0){ + monthDiff += monthDays[monthTest]; + if(Fmath.leapYear(year))monthDiff++; + monthTest--; + } + + monthDiff *= 24L*60L*60L*1000L; + + ms = yearDiff + monthDiff + day*24L*60L*60L*1000L + hour*60L*60L*1000L + min*60L*1000L + sec*1000L; + + return ms; + } + + // DEPRECATED METHODS + // Several methods have been revised and moved to classes ArrayMaths, Conv or PrintToScreen + + // ARRAY MAXIMUM (deprecated - see ArryMaths class) + // Maximum of a 1D array of doubles, aa + public static double maximum(double[] aa){ + int n = aa.length; + double aamax=aa[0]; + for(int i=1; i<n; i++){ + if(aa[i]>aamax)aamax=aa[i]; + } + return aamax; + } + + // Maximum of a 1D array of floats, aa + public static float maximum(float[] aa){ + int n = aa.length; + float aamax=aa[0]; + for(int i=1; i<n; i++){ + if(aa[i]>aamax)aamax=aa[i]; + } + return aamax; + } + + // Maximum of a 1D array of ints, aa + public static int maximum(int[] aa){ + int n = aa.length; + int aamax=aa[0]; + for(int i=1; i<n; i++){ + if(aa[i]>aamax)aamax=aa[i]; + } + return aamax; + } + + // Maximum of a 1D array of longs, aa + public static long maximum(long[] aa){ + long n = aa.length; + long aamax=aa[0]; + for(int i=1; i<n; i++){ + if(aa[i]>aamax)aamax=aa[i]; + } + return aamax; + } + + // Minimum of a 1D array of doubles, aa + public static double minimum(double[] aa){ + int n = aa.length; + double aamin=aa[0]; + for(int i=1; i<n; i++){ + if(aa[i]<aamin)aamin=aa[i]; + } + return aamin; + } + + // Minimum of a 1D array of floats, aa + public static float minimum(float[] aa){ + int n = aa.length; + float aamin=aa[0]; + for(int i=1; i<n; i++){ + if(aa[i]<aamin)aamin=aa[i]; + } + return aamin; + } + + // ARRAY MINIMUM (deprecated - see ArryMaths class) + // Minimum of a 1D array of ints, aa + public static int minimum(int[] aa){ + int n = aa.length; + int aamin=aa[0]; + for(int i=1; i<n; i++){ + if(aa[i]<aamin)aamin=aa[i]; + } + return aamin; + } + + // Minimum of a 1D array of longs, aa + public static long minimum(long[] aa){ + long n = aa.length; + long aamin=aa[0]; + for(int i=1; i<n; i++){ + if(aa[i]<aamin)aamin=aa[i]; + } + return aamin; + } + + // MAXIMUM DISTANCE BETWEEN ARRAY ELEMENTS (deprecated - see ArryMaths class) + // Maximum distance between elements of a 1D array of doubles, aa + public static double maximumDifference(double[] aa){ + return Fmath.maximum(aa) - Fmath.minimum(aa); + } + + // Maximum distance between elements of a 1D array of floats, aa + public static float maximumDifference(float[] aa){ + return Fmath.maximum(aa) - Fmath.minimum(aa); + } + + // Maximum distance between elements of a 1D array of long, aa + public static long maximumDifference(long[] aa){ + return Fmath.maximum(aa) - Fmath.minimum(aa); + } + + // Maximum distance between elements of a 1D array of ints, aa + public static int maximumDifference(int[] aa){ + return Fmath.maximum(aa) - Fmath.minimum(aa); + } + + + // MINIMUM DISTANCE BETWEEN ARRAY ELEMENTS (deprecated - see ArryMaths class) + // Minimum distance between elements of a 1D array of doubles, aa + public static double minimumDifference(double[] aa){ + double[] sorted = Fmath.selectionSort(aa); + double n = aa.length; + double diff = sorted[1] - sorted[0]; + double minDiff = diff; + for(int i=1; i<n-1; i++){ + diff = sorted[i+1] - sorted[i]; + if(diff<minDiff)minDiff = diff; + } + return minDiff; + } + + // Minimum distance between elements of a 1D array of floats, aa + public static float minimumDifference(float[] aa){ + float[] sorted = Fmath.selectionSort(aa); + float n = aa.length; + float diff = sorted[1] - sorted[0]; + float minDiff = diff; + for(int i=1; i<n-1; i++){ + diff = sorted[i+1] - sorted[i]; + if(diff<minDiff)minDiff = diff; + } + return minDiff; + } + + // Minimum distance between elements of a 1D array of longs, aa + public static long minimumDifference(long[] aa){ + long[] sorted = Fmath.selectionSort(aa); + long n = aa.length; + long diff = sorted[1] - sorted[0]; + long minDiff = diff; + for(int i=1; i<n-1; i++){ + diff = sorted[i+1] - sorted[i]; + if(diff<minDiff)minDiff = diff; + } + return minDiff; + } + + // Minimum distance between elements of a 1D array of ints, aa + public static int minimumDifference(int[] aa){ + int[] sorted = Fmath.selectionSort(aa); + int n = aa.length; + int diff = sorted[1] - sorted[0]; + int minDiff = diff; + for(int i=1; i<n-1; i++){ + diff = sorted[i+1] - sorted[i]; + if(diff<minDiff)minDiff = diff; + } + return minDiff; + } + + // REVERSE ORDER OF ARRAY ELEMENTS (deprecated - see ArryMaths class) + // Reverse the order of the elements of a 1D array of doubles, aa + public static double[] reverseArray(double[] aa){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = aa[n-1-i]; + } + return bb; + } + + // Reverse the order of the elements of a 1D array of floats, aa + public static float[] reverseArray(float[] aa){ + int n = aa.length; + float[] bb = new float[n]; + for(int i=0; i<n; i++){ + bb[i] = aa[n-1-i]; + } + return bb; + } + + // Reverse the order of the elements of a 1D array of ints, aa + public static int[] reverseArray(int[] aa){ + int n = aa.length; + int[] bb = new int[n]; + for(int i=0; i<n; i++){ + bb[i] = aa[n-1-i]; + } + return bb; + } + + // Reverse the order of the elements of a 1D array of longs, aa + public static long[] reverseArray(long[] aa){ + int n = aa.length; + long[] bb = new long[n]; + for(int i=0; i<n; i++){ + bb[i] = aa[n-1-i]; + } + return bb; + } + + // Reverse the order of the elements of a 1D array of char, aa + public static char[] reverseArray(char[] aa){ + int n = aa.length; + char[] bb = new char[n]; + for(int i=0; i<n; i++){ + bb[i] = aa[n-1-i]; + } + return bb; + } + + // ABSOLUTE VALUE OF ARRAY ELEMENTS (deprecated - see ArryMaths class) + // return absolute values of an array of doubles + public static double[] arrayAbs(double[] aa){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = Math.abs(aa[i]); + } + return bb; + } + + // return absolute values of an array of floats + public static float[] arrayAbs(float[] aa){ + int n = aa.length; + float[] bb = new float[n]; + for(int i=0; i<n; i++){ + bb[i] = Math.abs(aa[i]); + } + return bb; + } + + // return absolute values of an array of long + public static long[] arrayAbs(long[] aa){ + int n = aa.length; + long[] bb = new long[n]; + for(int i=0; i<n; i++){ + bb[i] = Math.abs(aa[i]); + } + return bb; + } + + // return absolute values of an array of int + public static int[] arrayAbs(int[] aa){ + int n = aa.length; + int[] bb = new int[n]; + for(int i=0; i<n; i++){ + bb[i] = Math.abs(aa[i]); + } + return bb; + } + + // MULTIPLY ARRAY ELEMENTS BY A CONSTANT (deprecated - see ArryMaths class) + // multiply all elements by a constant double[] by double -> double[] + public static double[] arrayMultByConstant(double[] aa, double constant){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = aa[i]*constant; + } + return bb; + } + + // multiply all elements by a constant int[] by double -> double[] + public static double[] arrayMultByConstant(int[] aa, double constant){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = (double)aa[i]*constant; + } + return bb; + } + // multiply all elements by a constant double[] by int -> double[] + public static double[] arrayMultByConstant(double[] aa, int constant){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = aa[i]*(double)constant; + } + return bb; + } + + // multiply all elements by a constant int[] by int -> double[] + public static double[] arrayMultByConstant(int[] aa, int constant){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = (double)(aa[i]*constant); + } + return bb; + } + + // LOG10 OF ARRAY ELEMENTS (deprecated - see ArryMaths class) + // Log to base 10 of all elements of an array of doubles + public static double[] log10Elements(double[] aa){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++)bb[i] = Math.log10(aa[i]); + return bb; + } + + // Log to base 10 of all elements of an array of floats + public static float[] log10Elements(float[] aa){ + int n = aa.length; + float[] bb = new float[n]; + for(int i=0; i<n; i++)bb[i] = (float)Math.log10(aa[i]); + return bb; + } + + // NATURAL LOG OF ARRAY ELEMENTS (deprecated - see ArryMaths class) + // Log to base e of all elements of an array of doubles + public static double[] lnElements(double[] aa){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++)bb[i] = Math.log10(aa[i]); + return bb; + } + + // Log to base e of all elements of an array of floats + public static float[] lnElements(float[] aa){ + int n = aa.length; + float[] bb = new float[n]; + for(int i=0; i<n; i++)bb[i] = (float)Math.log10(aa[i]); + return bb; + } + + // SQUARE ROOT OF ARRAY ELEMENTS (deprecated - see ArryMaths class) + // Square root all elements of an array of doubles + public static double[] squareRootElements(double[] aa){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++)bb[i] = Math.sqrt(aa[i]); + return bb; + } + + // Square root all elements of an array of floats + public static float[] squareRootElements(float[] aa){ + int n = aa.length; + float[] bb = new float[n]; + for(int i=0; i<n; i++)bb[i] = (float)Math.sqrt(aa[i]); + return bb; + } + + // POWER OF ARRAY ELEMENTS (deprecated - see ArryMaths class) + // Raise all elements of an array of doubles to a double power + public static double[] raiseElementsToPower(double[] aa, double power){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++)bb[i] = Math.pow(aa[i], power); + return bb; + } + + // Raise all elements of an array of doubles to an int power + public static double[] raiseElementsToPower(double[] aa, int power){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++)bb[i] = Math.pow(aa[i], power); + return bb; + } + + // Raise all elements of an array of floats to a float power + public static float[] raiseElementsToPower(float[] aa, float power){ + int n = aa.length; + float[] bb = new float[n]; + for(int i=0; i<n; i++)bb[i] = (float)Math.pow(aa[i], power); + return bb; + } + + // Raise all elements of an array of floats to an int power + public static float[] raiseElementsToPower(float[] aa, int power){ + int n = aa.length; + float[] bb = new float[n]; + for(int i=0; i<n; i++)bb[i] = (float)Math.pow(aa[i], power); + return bb; + } + + // INVERT ARRAY ELEMENTS (deprecated - see ArryMaths class) + // invert all elements of an array of doubles + public static double[] invertElements(double[] aa){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++)bb[i] = 1.0D/aa[i]; + return bb; + } + + // invert all elements of an array of floats + public static float[] invertElements(float[] aa){ + int n = aa.length; + float[] bb = new float[n]; + for(int i=0; i<n; i++)bb[i] = 1.0F/aa[i]; + return bb; + } + + + // FIND INDICES OF ARRAY ELEMENTS EQUAL TO A VALUE (deprecated - see ArryMaths class) + // finds the indices of the elements equal to a given value in an array of doubles + // returns null if none found + public static int[] indicesOf(double[] array, double value){ + int[] indices = null; + int numberOfIndices = 0; + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<array.length; i++){ + if(array[i]==value){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + return indices; + } + + // finds the indices of the elements equal to a given value in an array of floats + // returns null if none found + public static int[] indicesOf(float[] array, float value){ + int[] indices = null; + int numberOfIndices = 0; + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<array.length; i++){ + if(array[i]==value){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + return indices; + } + + // finds the indices of the elements equal to a given value in an array of longs + // returns null if none found + public static int[] indicesOf(long[] array, long value){ + int[] indices = null; + int numberOfIndices = 0; + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<array.length; i++){ + if(array[i]==value){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + return indices; + } + + // finds the indices of the elements equal to a given value in an array of ints + // returns null if none found + public static int[] indicesOf(int[] array, int value){ + int[] indices = null; + int numberOfIndices = 0; + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<array.length; i++){ + if(array[i]==value){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + return indices; + } + + // finds the indices of the elements equal to a given value in an array of shorts + // returns null if none found + public static int[] indicesOf(short[] array, short value){ + int[] indices = null; + int numberOfIndices = 0; + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<array.length; i++){ + if(array[i]==value){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + return indices; + } + + // finds the indices of the elements equal to a given value in an array of bytes + // returns null if none found + public static int[] indicesOf(byte[] array, byte value){ + int[] indices = null; + int numberOfIndices = 0; + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<array.length; i++){ + if(array[i]==value){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + return indices; + } + + // finds the indices of the elements equal to a given value in an array of chars + // returns null if none found + public static int[] indicesOf(char[] array, char value){ + int[] indices = null; + int numberOfIndices = 0; + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<array.length; i++){ + if(array[i]==value){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + return indices; + } + + // finds the indices of the elements equal to a given value in an array of Strings + // returns null if none found + public static int[] indicesOf(String[] array, String value){ + int[] indices = null; + int numberOfIndices = 0; + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<array.length; i++){ + if(array[i].equals(value)){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + return indices; + } + + // finds the indices of the elements equal to a given value in an array of Objectss + // returns null if none found + public static int[] indicesOf(Object[] array, Object value){ + int[] indices = null; + int numberOfIndices = 0; + ArrayList<Integer> arrayl = new ArrayList<Integer>(); + for(int i=0; i<array.length; i++){ + if(array[i].equals(value)){ + numberOfIndices++; + arrayl.add(new Integer(i)); + } + } + if(numberOfIndices!=0){ + indices = new int[numberOfIndices]; + for(int i=0; i<numberOfIndices; i++){ + indices[i] = (arrayl.get(i)).intValue(); + } + } + return indices; + } + + // FIND FIRST INDEX OF ARRAY ELEMENT EQUAL TO A VALUE (deprecated - see ArryMaths class) + // finds the index of the first occurence of the element equal to a given value in an array of doubles + // returns -1 if none found + public static int indexOf(double[] array, double value){ + int index = -1; + boolean test = true; + int counter = 0; + while(test){ + if(array[counter]==value){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=array.length)test = false; + } + } + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array of floats + // returns -1 if none found + public static int indexOf(float[] array, float value){ + int index = -1; + boolean test = true; + int counter = 0; + while(test){ + if(array[counter]==value){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=array.length)test = false; + } + } + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array of longs + // returns -1 if none found + public static int indexOf(long[] array, long value){ + int index = -1; + boolean test = true; + int counter = 0; + while(test){ + if(array[counter]==value){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=array.length)test = false; + } + } + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array of ints + // returns -1 if none found + public static int indexOf(int[] array, int value){ + int index = -1; + boolean test = true; + int counter = 0; + while(test){ + if(array[counter]==value){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=array.length)test = false; + } + } + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array of bytes + // returns -1 if none found + public static int indexOf(byte[] array, byte value){ + int index = -1; + boolean test = true; + int counter = 0; + while(test){ + if(array[counter]==value){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=array.length)test = false; + } + } + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array of shorts + // returns -1 if none found + public static int indexOf(short[] array, short value){ + int index = -1; + boolean test = true; + int counter = 0; + while(test){ + if(array[counter]==value){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=array.length)test = false; + } + } + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array of chars + // returns -1 if none found + public static int indexOf(char[] array, char value){ + int index = -1; + boolean test = true; + int counter = 0; + while(test){ + if(array[counter]==value){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=array.length)test = false; + } + } + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array of Strings + // returns -1 if none found + public static int indexOf(String[] array, String value){ + int index = -1; + boolean test = true; + int counter = 0; + while(test){ + if(array[counter].equals(value)){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=array.length)test = false; + } + } + return index; + } + + // finds the index of the first occurence of the element equal to a given value in an array of Objects + // returns -1 if none found + public static int indexOf(Object[] array, Object value){ + int index = -1; + boolean test = true; + int counter = 0; + while(test){ + if(array[counter].equals(value)){ + index = counter; + test = false; + } + else{ + counter++; + if(counter>=array.length)test = false; + } + } + return index; + } + + // FIND VALUE OF AND FIND VALUE OF ARRAY ELEMENTS NEAREST TO A VALUE (deprecated - see ArryMaths class) + // finds the value of nearest element value in array to the argument value + public static double nearestElementValue(double[] array, double value){ + double diff = Math.abs(array[0] - value); + double nearest = array[0]; + for(int i=1; i<array.length; i++){ + if(Math.abs(array[i] - value)<diff){ + diff = Math.abs(array[i] - value); + nearest = array[i]; + } + } + return nearest; + } + + // finds the index of nearest element value in array to the argument value + public static int nearestElementIndex(double[] array, double value){ + double diff = Math.abs(array[0] - value); + int nearest = 0; + for(int i=1; i<array.length; i++){ + if(Math.abs(array[i] - value)<diff){ + diff = Math.abs(array[i] - value); + nearest = i; + } + } + return nearest; + } + + // finds the value of nearest lower element value in array to the argument value + public static double nearestLowerElementValue(double[] array, double value){ + double diff0 = 0.0D; + double diff1 = 0.0D; + double nearest = 0.0D; + int ii = 0; + boolean test = true; + double min = array[0]; + while(test){ + if(array[ii]<min)min = array[ii]; + if((value - array[ii])>=0.0D){ + diff0 = value - array[ii]; + nearest = array[ii]; + test = false; + } + else{ + ii++; + if(ii>array.length-1){ + nearest = min; + diff0 = min - value; + test = false; + } + } + } + for(int i=0; i<array.length; i++){ + diff1 = value - array[i]; + if(diff1>=0.0D && diff1<diff0 ){ + diff0 = diff1; + nearest = array[i]; + } + } + return nearest; + } + + // finds the index of nearest lower element value in array to the argument value + public static int nearestLowerElementIndex(double[] array, double value){ + double diff0 = 0.0D; + double diff1 = 0.0D; + int nearest = 0; + int ii = 0; + boolean test = true; + double min = array[0]; + int minI = 0; + while(test){ + if(array[ii]<min){ + min = array[ii]; + minI = ii; + } + if((value - array[ii])>=0.0D){ + diff0 = value - array[ii]; + nearest = ii; + test = false; + } + else{ + ii++; + if(ii>array.length-1){ + nearest = minI; + diff0 = min - value; + test = false; + } + } + } + for(int i=0; i<array.length; i++){ + diff1 = value - array[i]; + if(diff1>=0.0D && diff1<diff0 ){ + diff0 = diff1; + nearest = i; + } + } + return nearest; + } + + // finds the value of nearest higher element value in array to the argument value + public static double nearestHigherElementValue(double[] array, double value){ + double diff0 = 0.0D; + double diff1 = 0.0D; + double nearest = 0.0D; + int ii = 0; + boolean test = true; + double max = array[0]; + while(test){ + if(array[ii]>max)max = array[ii]; + if((array[ii] - value )>=0.0D){ + diff0 = value - array[ii]; + nearest = array[ii]; + test = false; + } + else{ + ii++; + if(ii>array.length-1){ + nearest = max; + diff0 = value - max; + test = false; + } + } + } + for(int i=0; i<array.length; i++){ + diff1 = array[i]- value; + if(diff1>=0.0D && diff1<diff0 ){ + diff0 = diff1; + nearest = array[i]; + } + } + return nearest; + } + + // finds the index of nearest higher element value in array to the argument value + public static int nearestHigherElementIndex(double[] array, double value){ + double diff0 = 0.0D; + double diff1 = 0.0D; + int nearest = 0; + int ii = 0; + boolean test = true; + double max = array[0]; + int maxI = 0; + while(test){ + if(array[ii]>max){ + max = array[ii]; + maxI = ii; + } + if((array[ii] - value )>=0.0D){ + diff0 = value - array[ii]; + nearest = ii; + test = false; + } + else{ + ii++; + if(ii>array.length-1){ + nearest = maxI; + diff0 = value - max; + test = false; + } + } + } + for(int i=0; i<array.length; i++){ + diff1 = array[i]- value; + if(diff1>=0.0D && diff1<diff0 ){ + diff0 = diff1; + nearest = i; + } + } + return nearest; + } + + + // finds the value of nearest element value in array to the argument value + public static int nearestElementValue(int[] array, int value){ + int diff = Math.abs(array[0] - value); + int nearest = array[0]; + for(int i=1; i<array.length; i++){ + if(Math.abs(array[i] - value)<diff){ + diff = Math.abs(array[i] - value); + nearest = array[i]; + } + } + return nearest; + } + + // finds the index of nearest element value in array to the argument value + public static int nearestElementIndex(int[] array, int value){ + int diff = Math.abs(array[0] - value); + int nearest = 0; + for(int i=1; i<array.length; i++){ + if(Math.abs(array[i] - value)<diff){ + diff = Math.abs(array[i] - value); + nearest = i; + } + } + return nearest; + } + + // finds the value of nearest lower element value in array to the argument value + public static int nearestLowerElementValue(int[] array, int value){ + int diff0 = 0; + int diff1 = 0; + int nearest = 0; + int ii = 0; + boolean test = true; + int min = array[0]; + while(test){ + if(array[ii]<min)min = array[ii]; + if((value - array[ii])>=0){ + diff0 = value - array[ii]; + nearest = array[ii]; + test = false; + } + else{ + ii++; + if(ii>array.length-1){ + nearest = min; + diff0 = min - value; + test = false; + } + } + } + for(int i=0; i<array.length; i++){ + diff1 = value - array[i]; + if(diff1>=0 && diff1<diff0 ){ + diff0 = diff1; + nearest = array[i]; + } + } + return nearest; + } + + // finds the index of nearest lower element value in array to the argument value + public static int nearestLowerElementIndex(int[] array, int value){ + int diff0 = 0; + int diff1 = 0; + int nearest = 0; + int ii = 0; + boolean test = true; + int min = array[0]; + int minI = 0; + while(test){ + if(array[ii]<min){ + min = array[ii]; + minI = ii; + } + if((value - array[ii])>=0){ + diff0 = value - array[ii]; + nearest = ii; + test = false; + } + else{ + ii++; + if(ii>array.length-1){ + nearest = minI; + diff0 = min - value; + test = false; + } + } + } + for(int i=0; i<array.length; i++){ + diff1 = value - array[i]; + if(diff1>=0 && diff1<diff0 ){ + diff0 = diff1; + nearest = i; + } + } + return nearest; + } + + // finds the value of nearest higher element value in array to the argument value + public static int nearestHigherElementValue(int[] array, int value){ + int diff0 = 0; + int diff1 = 0; + int nearest = 0; + int ii = 0; + boolean test = true; + int max = array[0]; + while(test){ + if(array[ii]>max)max = array[ii]; + if((array[ii] - value )>=0){ + diff0 = value - array[ii]; + nearest = array[ii]; + test = false; + } + else{ + ii++; + if(ii>array.length-1){ + nearest = max; + diff0 = value - max; + test = false; + } + } + } + for(int i=0; i<array.length; i++){ + diff1 = array[i]- value; + if(diff1>=0 && diff1<diff0 ){ + diff0 = diff1; + nearest = array[i]; + } + } + return nearest; + } + + // finds the index of nearest higher element value in array to the argument value + public static int nearestHigherElementIndex(int[] array, int value){ + int diff0 = 0; + int diff1 = 0; + int nearest = 0; + int ii = 0; + boolean test = true; + int max = array[0]; + int maxI = 0; + while(test){ + if(array[ii]>max){ + max = array[ii]; + maxI = ii; + } + if((array[ii] - value )>=0){ + diff0 = value - array[ii]; + nearest = ii; + test = false; + } + else{ + ii++; + if(ii>array.length-1){ + nearest = maxI; + diff0 = value - max; + test = false; + } + } + } + for(int i=0; i<array.length; i++){ + diff1 = array[i]- value; + if(diff1>=0 && diff1<diff0 ){ + diff0 = diff1; + nearest = i; + } + } + return nearest; + } + + // SUM OF ALL ELEMENTS (deprecated - see ArryMaths class) + // Sum of all array elements - double array + public static double arraySum(double[]array){ + double sum = 0.0D; + for(double i:array)sum += i; + return sum; + } + + // Sum of all array elements - float array + public static float arraySum(float[]array){ + float sum = 0.0F; + for(float i:array)sum += i; + return sum; + } + + // Sum of all array elements - int array + public static int arraySum(int[]array){ + int sum = 0; + for(int i:array)sum += i; + return sum; + } + + // Sum of all array elements - long array + public static long arraySum(long[]array){ + long sum = 0L; + for(long i:array)sum += i; + return sum; + } + + // Sum of all positive array elements - long array + public static long arrayPositiveElementsSum(long[]array){ + long sum = 0L; + for(long i:array)if(i>0)sum += i; + return sum; + } + + + // PRODUCT OF ALL ELEMENTS (deprecated - see ArryMaths class) + // Product of all array elements - double array + public static double arrayProduct(double[]array){ + double product = 1.0D; + for(double i:array)product *= i; + return product; + } + + // Product of all array elements - float array + public static float arrayProduct(float[]array){ + float product = 1.0F; + for(float i:array)product *= i; + return product; + } + + // Product of all array elements - int array + public static int arrayProduct(int[]array){ + int product = 1; + for(int i:array)product *= i; + return product; + } + + // Product of all array elements - long array + public static long arrayProduct(long[]array){ + long product = 1L; + for(long i:array)product *= i; + return product; + } + + // CONCATENATE TWO ARRAYS (deprecated - see ArryMaths class) + // Concatenate two double arrays + public static double[] concatenate(double[] aa, double[] bb){ + int aLen = aa.length; + int bLen = bb.length; + int cLen = aLen + bLen; + double[] cc = new double[cLen]; + for(int i=0; i<aLen; i++){ + cc[i] = aa[i]; + } + for(int i=0; i<bLen; i++){ + cc[i+aLen] = bb[i]; + } + return cc; + } + + // Concatenate two float arrays + public static float[] concatenate(float[] aa, float[] bb){ + int aLen = aa.length; + int bLen = bb.length; + int cLen = aLen + bLen; + float[] cc = new float[cLen]; + for(int i=0; i<aLen; i++){ + cc[i] = aa[i]; + } + for(int i=0; i<bLen; i++){ + cc[i+aLen] = bb[i]; + } + + return cc; + } + + // Concatenate two int arrays + public static int[] concatenate(int[] aa, int[] bb){ + int aLen = aa.length; + int bLen = bb.length; + int cLen = aLen + bLen; + int[] cc = new int[cLen]; + for(int i=0; i<aLen; i++){ + cc[i] = aa[i]; + } + for(int i=0; i<bLen; i++){ + cc[i+aLen] = bb[i]; + } + + return cc; + } + + // Concatenate two long arrays + public static long[] concatenate(long[] aa, long[] bb){ + int aLen = aa.length; + int bLen = bb.length; + int cLen = aLen + bLen; + long[] cc = new long[cLen]; + for(int i=0; i<aLen; i++){ + cc[i] = aa[i]; + } + for(int i=0; i<bLen; i++){ + cc[i+aLen] = bb[i]; + } + + return cc; + } + + // Concatenate two short arrays + public static short[] concatenate(short[] aa, short[] bb){ + int aLen = aa.length; + int bLen = bb.length; + int cLen = aLen + bLen; + short[] cc = new short[cLen]; + for(int i=0; i<aLen; i++){ + cc[i] = aa[i]; + } + for(int i=0; i<bLen; i++){ + cc[i+aLen] = bb[i]; + } + return cc; + } + + // Concatenate two byte arrays + public static byte[] concatenate(byte[] aa, byte[] bb){ + int aLen = aa.length; + int bLen = bb.length; + int cLen = aLen + bLen; + byte[] cc = new byte[cLen]; + for(int i=0; i<aLen; i++){ + cc[i] = aa[i]; + } + for(int i=0; i<bLen; i++){ + cc[i+aLen] = bb[i]; + } + + return cc; + } + + // Concatenate two char arrays + public static char[] concatenate(char[] aa, char[] bb){ + int aLen = aa.length; + int bLen = bb.length; + int cLen = aLen + bLen; + char[] cc = new char[cLen]; + for(int i=0; i<aLen; i++){ + cc[i] = aa[i]; + } + for(int i=0; i<bLen; i++){ + cc[i+aLen] = bb[i]; + } + + return cc; + } + + // Concatenate two String arrays + public static String[] concatenate(String[] aa, String[] bb){ + int aLen = aa.length; + int bLen = bb.length; + int cLen = aLen + bLen; + String[] cc = new String[cLen]; + for(int i=0; i<aLen; i++){ + cc[i] = aa[i]; + } + for(int i=0; i<bLen; i++){ + cc[i+aLen] = bb[i]; + } + + return cc; + } + + // Concatenate two Object arrays + public static Object[] concatenate(Object[] aa, Object[] bb){ + int aLen = aa.length; + int bLen = bb.length; + int cLen = aLen + bLen; + Object[] cc = new Object[cLen]; + for(int i=0; i<aLen; i++){ + cc[i] = aa[i]; + } + for(int i=0; i<bLen; i++){ + cc[i+aLen] = bb[i]; + } + + return cc; + } + + // RECAST ARRAY TYPE (deprecated - see Conv class) + // recast an array of float as doubles + public static double[] floatTOdouble(float[] aa){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = (double)aa[i]; + } + return bb; + } + + // recast an array of int as double + public static double[] intTOdouble(int[] aa){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = (double)aa[i]; + } + return bb; + } + + // recast an array of int as float + public static float[] intTOfloat(int[] aa){ + int n = aa.length; + float[] bb = new float[n]; + for(int i=0; i<n; i++){ + bb[i] = (float)aa[i]; + } + return bb; + } + + // recast an array of int as long + public static long[] intTOlong(int[] aa){ + int n = aa.length; + long[] bb = new long[n]; + for(int i=0; i<n; i++){ + bb[i] = (long)aa[i]; + } + return bb; + } + + // recast an array of long as double + // BEWARE POSSIBLE LOSS OF PRECISION + public static double[] longTOdouble(long[] aa){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = (double)aa[i]; + } + return bb; + } + + // recast an array of long as float + // BEWARE POSSIBLE LOSS OF PRECISION + public static float[] longTOfloat(long[] aa){ + int n = aa.length; + float[] bb = new float[n]; + for(int i=0; i<n; i++){ + bb[i] = (float)aa[i]; + } + return bb; + } + + // recast an array of short as double + public static double[] shortTOdouble(short[] aa){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = (double)aa[i]; + } + return bb; + } + + // recast an array of short as float + public static float[] shortTOfloat(short[] aa){ + int n = aa.length; + float[] bb = new float[n]; + for(int i=0; i<n; i++){ + bb[i] = (float)aa[i]; + } + return bb; + } + + // recast an array of short as long + public static long[] shortTOlong(short[] aa){ + int n = aa.length; + long[] bb = new long[n]; + for(int i=0; i<n; i++){ + bb[i] = (long)aa[i]; + } + return bb; + } + + // recast an array of short as int + public static int[] shortTOint(short[] aa){ + int n = aa.length; + int[] bb = new int[n]; + for(int i=0; i<n; i++){ + bb[i] = (int)aa[i]; + } + return bb; + } + + // recast an array of byte as double + public static double[] byteTOdouble(byte[] aa){ + int n = aa.length; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i] = (int)aa[i]; + } + return bb; + } + + // recast an array of byte as float + public static float[] byteTOfloat(byte[] aa){ + int n = aa.length; + float[] bb = new float[n]; + for(int i=0; i<n; i++){ + bb[i] = (float)aa[i]; + } + return bb; + } + + // recast an array of byte as long + public static long[] byteTOlong(byte[] aa){ + int n = aa.length; + long[] bb = new long[n]; + for(int i=0; i<n; i++){ + bb[i] = (long)aa[i]; + } + return bb; + } + + // recast an array of byte as int + public static int[] byteTOint(byte[] aa){ + int n = aa.length; + int[] bb = new int[n]; + for(int i=0; i<n; i++){ + bb[i] = (int)aa[i]; + } + return bb; + } + + // recast an array of byte as short + public static short[] byteTOshort(byte[] aa){ + int n = aa.length; + short[] bb = new short[n]; + for(int i=0; i<n; i++){ + bb[i] = (short)aa[i]; + } + return bb; + } + + // recast an array of double as int + // BEWARE OF LOSS OF PRECISION + public static int[] doubleTOint(double[] aa){ + int n = aa.length; + int[] bb = new int[n]; + for(int i=0; i<n; i++){ + bb[i] = (int)aa[i]; + } + return bb; + } + + // PRINT ARRAY TO SCREEN (deprecated - see PrintToScreen class) + // print an array of doubles to screen + // No line returns except at the end + public static void print(double[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of doubles to screen + // with line returns + public static void println(double[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of floats to screen + // No line returns except at the end + public static void print(float[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of floats to screen + // with line returns + public static void println(float[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of ints to screen + // No line returns except at the end + public static void print(int[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of ints to screen + // with line returns + public static void println(int[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of longs to screen + // No line returns except at the end + public static void print(long[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of longs to screen + // with line returns + public static void println(long[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of char to screen + // No line returns except at the end + public static void print(char[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of char to screen + // with line returns + public static void println(char[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of String to screen + // No line returns except at the end + public static void print(String[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of Strings to screen + // with line returns + public static void println(String[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of shorts to screen + // No line returns except at the end + public static void print(short[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of shorts to screen + // with line returns + public static void println(short[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + // print an array of bytes to screen + // No line returns except at the end + public static void print(byte[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.print(aa[i]+" "); + } + System.out.println(); + } + + // print an array of bytes to screen + // with line returns + public static void println(byte[] aa){ + for(int i=0; i<aa.length; i++){ + System.out.println(aa[i]+" "); + } + } + + + // print a 2D array of doubles to screen + public static void print(double[][] aa){ + for(int i=0; i<aa.length; i++){ + Fmath.print(aa[i]); + } + } + + // SORT ELEMENTS OF ARRAY (deprecated - see ArryMaths class) + // sort elements in an array of doubles into ascending order + // using selection sort method + // returns Vector containing the original array, the sorted array + // and an array of the indices of the sorted array + public static Vector<Object> selectSortVector(double[] aa){ + ArrayList<Object> list = Fmath.selectSortArrayList(aa); + Vector<Object> ret = null; + if(list!=null){ + int n = list.size(); + ret = new Vector<Object>(n); + for(int i=0; i<n; i++)ret.addElement(list.get(i)); + } + return ret; + } + + + // sort elements in an array of doubles into ascending order + // using selection sort method + // returns ArrayList containing the original array, the sorted array + // and an array of the indices of the sorted array + public static ArrayList<Object> selectSortArrayList(double[] aa){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + double holdb = 0.0D; + int holdi = 0; + double[] bb = new double[n]; + int[] indices = new int[n]; + for(int i=0; i<n; i++){ + bb[i]=aa[i]; + indices[i]=i; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(bb[i]<bb[index]){ + index=i; + } + } + lastIndex++; + holdb=bb[index]; + bb[index]=bb[lastIndex]; + bb[lastIndex]=holdb; + holdi=indices[index]; + indices[index]=indices[lastIndex]; + indices[lastIndex]=holdi; + } + ArrayList<Object> arrayl = new ArrayList<Object>(); + arrayl.add(aa); + arrayl.add(bb); + arrayl.add(indices); + return arrayl; + } + + // sort elements in an array of doubles into ascending order + // using selection sort method + public static double[] selectionSort(double[] aa){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + double hold = 0.0D; + double[] bb = new double[n]; + for(int i=0; i<n; i++){ + bb[i]=aa[i]; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(bb[i]<bb[index]){ + index=i; + } + } + lastIndex++; + hold=bb[index]; + bb[index]=bb[lastIndex]; + bb[lastIndex]=hold; + } + return bb; + } + + // sort elements in an array of floats into ascending order + // using selection sort method + public static float[] selectionSort(float[] aa){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + float hold = 0.0F; + float[] bb = new float[n]; + for(int i=0; i<n; i++){ + bb[i]=aa[i]; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(bb[i]<bb[index]){ + index=i; + } + } + lastIndex++; + hold=bb[index]; + bb[index]=bb[lastIndex]; + bb[lastIndex]=hold; + } + return bb; + } + + // sort elements in an array of ints into ascending order + // using selection sort method + public static int[] selectionSort(int[] aa){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + int hold = 0; + int[] bb = new int[n]; + for(int i=0; i<n; i++){ + bb[i]=aa[i]; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(bb[i]<bb[index]){ + index=i; + } + } + lastIndex++; + hold=bb[index]; + bb[index]=bb[lastIndex]; + bb[lastIndex]=hold; + } + return bb; + } + + // sort elements in an array of longs into ascending order + // using selection sort method + public static long[] selectionSort(long[] aa){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + long hold = 0L; + long[] bb = new long[n]; + for(int i=0; i<n; i++){ + bb[i]=aa[i]; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(bb[i]<bb[index]){ + index=i; + } + } + lastIndex++; + hold=bb[index]; + bb[index]=bb[lastIndex]; + bb[lastIndex]=hold; + } + return bb; + } + + // sort elements in an array of doubles into ascending order + // using selection sort method + // aa - the original array - not altered + // bb - the sorted array + // indices - an array of the original indices of the sorted array + public static void selectionSort(double[] aa, double[] bb, int[] indices){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + double holdb = 0.0D; + int holdi = 0; + for(int i=0; i<n; i++){ + bb[i]=aa[i]; + indices[i]=i; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(bb[i]<bb[index]){ + index=i; + } + } + lastIndex++; + holdb=bb[index]; + bb[index]=bb[lastIndex]; + bb[lastIndex]=holdb; + holdi=indices[index]; + indices[index]=indices[lastIndex]; + indices[lastIndex]=holdi; + } + } + + // sort the elements of an array of doubles into ascending order with matching switches in an array of the length + // using selection sort method + // array determining the order is the first argument + // matching array is the second argument + // sorted arrays returned as third and fourth arguments respectively + public static void selectionSort(double[] aa, double[] bb, double[] cc, double[] dd){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + int m = bb.length; + if(n!=m)throw new IllegalArgumentException("First argument array, aa, (length = " + n + ") and the second argument array, bb, (length = " + m + ") should be the same length"); + int nn = cc.length; + if(nn<n)throw new IllegalArgumentException("The third argument array, cc, (length = " + nn + ") should be at least as long as the first argument array, aa, (length = " + n + ")"); + int mm = dd.length; + if(mm<m)throw new IllegalArgumentException("The fourth argument array, dd, (length = " + mm + ") should be at least as long as the second argument array, bb, (length = " + m + ")"); + + double holdx = 0.0D; + double holdy = 0.0D; + + + for(int i=0; i<n; i++){ + cc[i]=aa[i]; + dd[i]=bb[i]; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(cc[i]<cc[index]){ + index=i; + } + } + lastIndex++; + holdx=cc[index]; + cc[index]=cc[lastIndex]; + cc[lastIndex]=holdx; + holdy=dd[index]; + dd[index]=dd[lastIndex]; + dd[lastIndex]=holdy; + } + } + + // sort the elements of an array of floats into ascending order with matching switches in an array of the length + // using selection sort method + // array determining the order is the first argument + // matching array is the second argument + // sorted arrays returned as third and fourth arguments respectively + public static void selectionSort(float[] aa, float[] bb, float[] cc, float[] dd){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + int m = bb.length; + if(n!=m)throw new IllegalArgumentException("First argument array, aa, (length = " + n + ") and the second argument array, bb, (length = " + m + ") should be the same length"); + int nn = cc.length; + if(nn<n)throw new IllegalArgumentException("The third argument array, cc, (length = " + nn + ") should be at least as long as the first argument array, aa, (length = " + n + ")"); + int mm = dd.length; + if(mm<m)throw new IllegalArgumentException("The fourth argument array, dd, (length = " + mm + ") should be at least as long as the second argument array, bb, (length = " + m + ")"); + + float holdx = 0.0F; + float holdy = 0.0F; + + + for(int i=0; i<n; i++){ + cc[i]=aa[i]; + dd[i]=bb[i]; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(cc[i]<cc[index]){ + index=i; + } + } + lastIndex++; + holdx=cc[index]; + cc[index]=cc[lastIndex]; + cc[lastIndex]=holdx; + holdy=dd[index]; + dd[index]=dd[lastIndex]; + dd[lastIndex]=holdy; + } + } + + // sort the elements of an longs of doubles into ascending order with matching switches in an array of the length + // using selection sort method + // array determining the order is the first argument + // matching array is the second argument + // sorted arrays returned as third and fourth arguments respectively + public static void selectionSort(long[] aa, long[] bb, long[] cc, long[] dd){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + int m = bb.length; + if(n!=m)throw new IllegalArgumentException("First argument array, aa, (length = " + n + ") and the second argument array, bb, (length = " + m + ") should be the same length"); + int nn = cc.length; + if(nn<n)throw new IllegalArgumentException("The third argument array, cc, (length = " + nn + ") should be at least as long as the first argument array, aa, (length = " + n + ")"); + int mm = dd.length; + if(mm<m)throw new IllegalArgumentException("The fourth argument array, dd, (length = " + mm + ") should be at least as long as the second argument array, bb, (length = " + m + ")"); + + long holdx = 0L; + long holdy = 0L; + + + for(int i=0; i<n; i++){ + cc[i]=aa[i]; + dd[i]=bb[i]; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(cc[i]<cc[index]){ + index=i; + } + } + lastIndex++; + holdx=cc[index]; + cc[index]=cc[lastIndex]; + cc[lastIndex]=holdx; + holdy=dd[index]; + dd[index]=dd[lastIndex]; + dd[lastIndex]=holdy; + } + } + + // sort the elements of an array of ints into ascending order with matching switches in an array of the length + // using selection sort method + // array determining the order is the first argument + // matching array is the second argument + // sorted arrays returned as third and fourth arguments respectively + public static void selectionSort(int[] aa, int[] bb, int[] cc, int[] dd){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + int m = bb.length; + if(n!=m)throw new IllegalArgumentException("First argument array, aa, (length = " + n + ") and the second argument array, bb, (length = " + m + ") should be the same length"); + int nn = cc.length; + if(nn<n)throw new IllegalArgumentException("The third argument array, cc, (length = " + nn + ") should be at least as long as the first argument array, aa, (length = " + n + ")"); + int mm = dd.length; + if(mm<m)throw new IllegalArgumentException("The fourth argument array, dd, (length = " + mm + ") should be at least as long as the second argument array, bb, (length = " + m + ")"); + + int holdx = 0; + int holdy = 0; + + + for(int i=0; i<n; i++){ + cc[i]=aa[i]; + dd[i]=bb[i]; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(cc[i]<cc[index]){ + index=i; + } + } + lastIndex++; + holdx=cc[index]; + cc[index]=cc[lastIndex]; + cc[lastIndex]=holdx; + holdy=dd[index]; + dd[index]=dd[lastIndex]; + dd[lastIndex]=holdy; + } + } + + // sort the elements of an array of doubles into ascending order with matching switches in an array of long of the length + // using selection sort method + // array determining the order is the first argument + // matching array is the second argument + // sorted arrays returned as third and fourth arguments respectively + public static void selectionSort(double[] aa, long[] bb, double[] cc, long[] dd){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + int m = bb.length; + if(n!=m)throw new IllegalArgumentException("First argument array, aa, (length = " + n + ") and the second argument array, bb, (length = " + m + ") should be the same length"); + int nn = cc.length; + if(nn<n)throw new IllegalArgumentException("The third argument array, cc, (length = " + nn + ") should be at least as long as the first argument array, aa, (length = " + n + ")"); + int mm = dd.length; + if(mm<m)throw new IllegalArgumentException("The fourth argument array, dd, (length = " + mm + ") should be at least as long as the second argument array, bb, (length = " + m + ")"); + + double holdx = 0.0D; + long holdy = 0L; + + + for(int i=0; i<n; i++){ + cc[i]=aa[i]; + dd[i]=bb[i]; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(cc[i]<cc[index]){ + index=i; + } + } + lastIndex++; + holdx=cc[index]; + cc[index]=cc[lastIndex]; + cc[lastIndex]=holdx; + holdy=dd[index]; + dd[index]=dd[lastIndex]; + dd[lastIndex]=holdy; + } + } + + // sort the elements of an array of long into ascending order with matching switches in an array of double of the length + // using selection sort method + // array determining the order is the first argument + // matching array is the second argument + // sorted arrays returned as third and fourth arguments respectively + public static void selectionSort(long[] aa, double[] bb, long[] cc, double[] dd){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + int m = bb.length; + if(n!=m)throw new IllegalArgumentException("First argument array, aa, (length = " + n + ") and the second argument array, bb, (length = " + m + ") should be the same length"); + int nn = cc.length; + if(nn<n)throw new IllegalArgumentException("The third argument array, cc, (length = " + nn + ") should be at least as long as the first argument array, aa, (length = " + n + ")"); + int mm = dd.length; + if(mm<m)throw new IllegalArgumentException("The fourth argument array, dd, (length = " + mm + ") should be at least as long as the second argument array, bb, (length = " + m + ")"); + + long holdx = 0L; + double holdy = 0.0D; + + + for(int i=0; i<n; i++){ + cc[i]=aa[i]; + dd[i]=bb[i]; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(cc[i]<cc[index]){ + index=i; + } + } + lastIndex++; + holdx=cc[index]; + cc[index]=cc[lastIndex]; + cc[lastIndex]=holdx; + holdy=dd[index]; + dd[index]=dd[lastIndex]; + dd[lastIndex]=holdy; + } + } + + // sort the elements of an array of doubles into ascending order with matching switches in an array of int of the length + // using selection sort method + // array determining the order is the first argument + // matching array is the second argument + // sorted arrays returned as third and fourth arguments respectively + public static void selectionSort(double[] aa, int[] bb, double[] cc, int[] dd){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + int m = bb.length; + if(n!=m)throw new IllegalArgumentException("First argument array, aa, (length = " + n + ") and the second argument array, bb, (length = " + m + ") should be the same length"); + int nn = cc.length; + if(nn<n)throw new IllegalArgumentException("The third argument array, cc, (length = " + nn + ") should be at least as long as the first argument array, aa, (length = " + n + ")"); + int mm = dd.length; + if(mm<m)throw new IllegalArgumentException("The fourth argument array, dd, (length = " + mm + ") should be at least as long as the second argument array, bb, (length = " + m + ")"); + + double holdx = 0.0D; + int holdy = 0; + + + for(int i=0; i<n; i++){ + cc[i]=aa[i]; + dd[i]=bb[i]; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(cc[i]<cc[index]){ + index=i; + } + } + lastIndex++; + holdx=cc[index]; + cc[index]=cc[lastIndex]; + cc[lastIndex]=holdx; + holdy=dd[index]; + dd[index]=dd[lastIndex]; + dd[lastIndex]=holdy; + } + } + + // sort the elements of an array of int into ascending order with matching switches in an array of double of the length + // using selection sort method + // array determining the order is the first argument + // matching array is the second argument + // sorted arrays returned as third and fourth arguments respectively + public static void selectionSort(int[] aa, double[] bb, int[] cc, double[] dd){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + int m = bb.length; + if(n!=m)throw new IllegalArgumentException("First argument array, aa, (length = " + n + ") and the second argument array, bb, (length = " + m + ") should be the same length"); + int nn = cc.length; + if(nn<n)throw new IllegalArgumentException("The third argument array, cc, (length = " + nn + ") should be at least as long as the first argument array, aa, (length = " + n + ")"); + int mm = dd.length; + if(mm<m)throw new IllegalArgumentException("The fourth argument array, dd, (length = " + mm + ") should be at least as long as the second argument array, bb, (length = " + m + ")"); + + int holdx = 0; + double holdy = 0.0D; + + + for(int i=0; i<n; i++){ + cc[i]=aa[i]; + dd[i]=bb[i]; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(cc[i]<cc[index]){ + index=i; + } + } + lastIndex++; + holdx=cc[index]; + cc[index]=cc[lastIndex]; + cc[lastIndex]=holdx; + holdy=dd[index]; + dd[index]=dd[lastIndex]; + dd[lastIndex]=holdy; + } + } + + // sort the elements of an array of long into ascending order with matching switches in an array of int of the length + // using selection sort method + // array determining the order is the first argument + // matching array is the second argument + // sorted arrays returned as third and fourth arguments respectively + public static void selectionSort(long[] aa, int[] bb, long[] cc, int[] dd){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + int m = bb.length; + if(n!=m)throw new IllegalArgumentException("First argument array, aa, (length = " + n + ") and the second argument array, bb, (length = " + m + ") should be the same length"); + int nn = cc.length; + if(nn<n)throw new IllegalArgumentException("The third argument array, cc, (length = " + nn + ") should be at least as long as the first argument array, aa, (length = " + n + ")"); + int mm = dd.length; + if(mm<m)throw new IllegalArgumentException("The fourth argument array, dd, (length = " + mm + ") should be at least as long as the second argument array, bb, (length = " + m + ")"); + + long holdx = 0L; + int holdy = 0; + + + for(int i=0; i<n; i++){ + cc[i]=aa[i]; + dd[i]=bb[i]; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(cc[i]<cc[index]){ + index=i; + } + } + lastIndex++; + holdx=cc[index]; + cc[index]=cc[lastIndex]; + cc[lastIndex]=holdx; + holdy=dd[index]; + dd[index]=dd[lastIndex]; + dd[lastIndex]=holdy; + } + } + + // sort the elements of an array of int into ascending order with matching switches in an array of long of the length + // using selection sort method + // array determining the order is the first argument + // matching array is the second argument + // sorted arrays returned as third and fourth arguments respectively + public static void selectionSort(int[] aa, long[] bb, int[] cc, long[] dd){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + int m = bb.length; + if(n!=m)throw new IllegalArgumentException("First argument array, aa, (length = " + n + ") and the second argument array, bb, (length = " + m + ") should be the same length"); + int nn = cc.length; + if(nn<n)throw new IllegalArgumentException("The third argument array, cc, (length = " + nn + ") should be at least as long as the first argument array, aa, (length = " + n + ")"); + int mm = dd.length; + if(mm<m)throw new IllegalArgumentException("The fourth argument array, dd, (length = " + mm + ") should be at least as long as the second argument array, bb, (length = " + m + ")"); + + int holdx = 0; + long holdy = 0L; + + + for(int i=0; i<n; i++){ + cc[i]=aa[i]; + dd[i]=bb[i]; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(cc[i]<cc[index]){ + index=i; + } + } + lastIndex++; + holdx=cc[index]; + cc[index]=cc[lastIndex]; + cc[lastIndex]=holdx; + holdy=dd[index]; + dd[index]=dd[lastIndex]; + dd[lastIndex]=holdy; + } + } + + + // sort elements in an array of doubles (first argument) into ascending order + // using selection sort method + // returns the sorted array as second argument + // and an array of the indices of the sorted array as the third argument + // same as corresponding selectionSort - retained for backward compatibility + public static void selectSort(double[] aa, double[] bb, int[] indices){ + int index = 0; + int lastIndex = -1; + int n = aa.length; + int m = bb.length; + if(m<n)throw new IllegalArgumentException("The second argument array, bb, (length = " + m + ") should be at least as long as the first argument array, aa, (length = " + n + ")"); + int k = indices.length; + if(m<n)throw new IllegalArgumentException("The third argument array, indices, (length = " + k + ") should be at least as long as the first argument array, aa, (length = " + n + ")"); + + double holdb = 0.0D; + int holdi = 0; + for(int i=0; i<n; i++){ + bb[i]=aa[i]; + indices[i]=i; + } + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(bb[i]<bb[index]){ + index=i; + } + } + lastIndex++; + holdb=bb[index]; + bb[index]=bb[lastIndex]; + bb[lastIndex]=holdb; + holdi=indices[index]; + indices[index]=indices[lastIndex]; + indices[lastIndex]=holdi; + } + } + + // COPY OF AN OBJECT (deprecated - see Conv class) + // Returns a copy of the object + // An exception will be thrown if an attempt to copy a non-serialisable object is made. + // Taken, with minor changes, from { Java Techniques } + // http://javatechniques.com/blog/ + public static Object copyObject(Object obj) { + Object objCopy = null; + try { + // Write the object out to a byte array + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(obj); + oos.flush(); + oos.close(); + // Make an input stream from the byte array and + // read a copy of the object back in. + ObjectInputStream ois = new ObjectInputStream( + new ByteArrayInputStream(bos.toByteArray())); + objCopy = ois.readObject(); + } + catch(IOException e) { + e.printStackTrace(); + } + catch(ClassNotFoundException cnfe) { + cnfe.printStackTrace(); + } + return objCopy; + } + + // UNIT CONVERSIONS (deprecated - see Conv class) + + // Converts radians to degrees + public static double radToDeg(double rad){ + return rad*180.0D/Math.PI; + } + + // Converts degrees to radians + public static double degToRad(double deg){ + return deg*Math.PI/180.0D; + } + + // Converts frequency (Hz) to radial frequency + public static double frequencyToRadialFrequency(double frequency){ + return 2.0D*Math.PI*frequency; + } + + // Converts radial frequency to frequency (Hz) + public static double radialFrequencyToFrequency(double radial){ + return radial/(2.0D*Math.PI); + } + + // Converts electron volts(eV) to corresponding wavelength in nm + public static double evToNm(double ev){ + return 1e+9*C_LIGHT/(-ev*Q_ELECTRON/H_PLANCK); + } + + // Converts wavelength in nm to matching energy in eV + public static double nmToEv(double nm) + { + return C_LIGHT/(-nm*1e-9)*H_PLANCK/Q_ELECTRON; + } + + // Converts moles per litre to percentage weight by volume + public static double molarToPercentWeightByVol(double molar, double molWeight){ + return molar*molWeight/10.0D; + } + + // Converts percentage weight by volume to moles per litre + public static double percentWeightByVolToMolar(double perCent, double molWeight){ + return perCent*10.0D/molWeight; + } + + // Converts Celsius to Kelvin + public static double celsiusToKelvin(double cels){ + return cels-T_ABS; + } + + // Converts Kelvin to Celsius + public static double kelvinToCelsius(double kelv){ + return kelv+T_ABS; + } + + // Converts Celsius to Fahrenheit + public static double celsiusToFahren(double cels){ + return cels*(9.0/5.0)+32.0; + } + + // Converts Fahrenheit to Celsius + public static double fahrenToCelsius(double fahr){ + return (fahr-32.0)*5.0/9.0; + } + + // Converts calories to Joules + public static double calorieToJoule(double cal){ + return cal*4.1868; + } + + // Converts Joules to calories + public static double jouleToCalorie(double joule){ + return joule*0.23884; + } + + // Converts grams to ounces + public static double gramToOunce(double gm){ + return gm/28.3459; + } + + // Converts ounces to grams + public static double ounceToGram(double oz){ + return oz*28.3459; + } + + // Converts kilograms to pounds + public static double kgToPound(double kg){ + return kg/0.4536; + } + + // Converts pounds to kilograms + public static double poundToKg(double pds){ + return pds*0.4536; + } + + // Converts kilograms to tons + public static double kgToTon(double kg){ + return kg/1016.05; + } + + // Converts tons to kilograms + public static double tonToKg(double tons){ + return tons*1016.05; + } + + // Converts millimetres to inches + public static double millimetreToInch(double mm){ + return mm/25.4; + } + + // Converts inches to millimetres + public static double inchToMillimetre(double in){ + return in*25.4; + } + + // Converts feet to metres + public static double footToMetre(double ft){ + return ft*0.3048; + } + + // Converts metres to feet + public static double metreToFoot(double metre){ + return metre/0.3048; + } + + // Converts yards to metres + public static double yardToMetre(double yd){ + return yd*0.9144; + } + + // Converts metres to yards + public static double metreToYard(double metre){ + return metre/0.9144; + } + + // Converts miles to kilometres + public static double mileToKm(double mile){ + return mile*1.6093; + } + + // Converts kilometres to miles + public static double kmToMile(double km){ + return km/1.6093; + } + + // Converts UK gallons to litres + public static double gallonToLitre(double gall){ + return gall*4.546; + } + + // Converts litres to UK gallons + public static double litreToGallon(double litre){ + return litre/4.546; + } + + // Converts UK quarts to litres + public static double quartToLitre(double quart){ + return quart*1.137; + } + + // Converts litres to UK quarts + public static double litreToQuart(double litre){ + return litre/1.137; + } + + // Converts UK pints to litres + public static double pintToLitre(double pint){ + return pint*0.568; + } + + // Converts litres to UK pints + public static double litreToPint(double litre){ + return litre/0.568; + } + + // Converts UK gallons per mile to litres per kilometre + public static double gallonPerMileToLitrePerKm(double gallPmile){ + return gallPmile*2.825; + } + + // Converts litres per kilometre to UK gallons per mile + public static double litrePerKmToGallonPerMile(double litrePkm){ + return litrePkm/2.825; + } + + // Converts miles per UK gallons to kilometres per litre + public static double milePerGallonToKmPerLitre(double milePgall){ + return milePgall*0.354; + } + + // Converts kilometres per litre to miles per UK gallons + public static double kmPerLitreToMilePerGallon(double kmPlitre){ + return kmPlitre/0.354; + } + + // Converts UK fluid ounce to American fluid ounce + public static double fluidOunceUKtoUS(double flOzUK){ + return flOzUK*0.961; + } + + // Converts American fluid ounce to UK fluid ounce + public static double fluidOunceUStoUK(double flOzUS){ + return flOzUS*1.041; + } + + // Converts UK pint to American liquid pint + public static double pintUKtoUS(double pintUK){ + return pintUK*1.201; + } + + // Converts American liquid pint to UK pint + public static double pintUStoUK(double pintUS){ + return pintUS*0.833; + } + + // Converts UK quart to American liquid quart + public static double quartUKtoUS(double quartUK){ + return quartUK*1.201; + } + + // Converts American liquid quart to UK quart + public static double quartUStoUK(double quartUS){ + return quartUS*0.833; + } + + // Converts UK gallon to American gallon + public static double gallonUKtoUS(double gallonUK){ + return gallonUK*1.201; + } + + // Converts American gallon to UK gallon + public static double gallonUStoUK(double gallonUS){ + return gallonUS*0.833; + } + + // Converts UK pint to American cup + public static double pintUKtoCupUS(double pintUK){ + return pintUK/0.417; + } + + // Converts American cup to UK pint + public static double cupUStoPintUK(double cupUS){ + return cupUS*0.417; + } + + // Calculates body mass index (BMI) from height (m) and weight (kg) + public static double calcBMImetric(double height, double weight){ + return weight/(height*height); + } + + // Calculates body mass index (BMI) from height (ft) and weight (lbs) + public static double calcBMIimperial(double height, double weight){ + height = Fmath.footToMetre(height); + weight = Fmath.poundToKg(weight); + return weight/(height*height); + } + + // Calculates weight (kg) to give a specified BMI for a given height (m) + public static double calcWeightFromBMImetric(double bmi, double height){ + return bmi*height*height; + } + + // Calculates weight (lbs) to give a specified BMI for a given height (ft) + public static double calcWeightFromBMIimperial(double bmi, double height){ + height = Fmath.footToMetre(height); + double weight = bmi*height*height; + weight = Fmath.kgToPound(weight); + return weight; + } +} + diff --git a/src/main/java/flanagan/math/FourierTransform.java b/src/main/java/flanagan/math/FourierTransform.java new file mode 100755 index 0000000000000000000000000000000000000000..4fcc7e8624f6f7aa3dabf40fb70393542c2dcfc4 --- /dev/null +++ b/src/main/java/flanagan/math/FourierTransform.java @@ -0,0 +1,2847 @@ +/* +* Fourier Transform +* +* This class contains the method for performing a +* Fast Fourier Transform (FFT) and associated methods +* e.g. for estimation of a power spectrum, for windowing data, +* obtaining a time-frequency representation. +* Basic FFT method is adapted from the Numerical Recipes +* methods written in the C language: +* Numerical Recipes in C, The Art of Scientific Computing, +* W.H. Press, S.A. Teukolsky, W.T. Vetterling & B.P. Flannery, +* Cambridge University Press, 2nd Edition (1992) pp 496 - 558. +* (http://www.nr.com/). +* +* AUTHOR: Dr Michael Thomas Flanagan +* DATE: 20 December 2003 +* UPDATES: 26 July 2004, 31 August 2004, 15 June 2005, 27 January 2006 +* UPDATES: 18 February 2006 method correlation correction (thanks to Daniel Mader, Universtät Freiburg -- IMTEK) + 7 July 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/FourierTranasform.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* +* Copyright (c) 2003 - 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.math; + +import flanagan.math.*; +import flanagan.io.*; +import java.io.Serializable; +import flanagan.complex.*; +import flanagan.plot.*; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.JFrame; + + +public class FourierTransform extends Canvas implements Serializable{ + + private static final long serialVersionUID = 1L; // serial version unique identifier + + private Complex[] complexData = null; // array to hold the input data as a set of Complex numbers + private Complex[] complexCorr = null; // corresponding array to hold the data to be correlated with first data set + private boolean complexDataSet = false; // if true - the complex data input array has been filled, if false - it has not. + private int originalDataLength = 0; // original data length value; the working data length may be altered by deletion or padding + private int fftDataLength = 0; // working data length - usually the smallest power of two that is either equal to originalDataLength or larger than originalDataLength + private boolean dataAltered = false; // set to true if originalDataLength altered, e.g. by point deletion or padding. + + private double[] fftData = null; // array to hold a data set of complex numbers arranged as alternating + // real and imaginary parts, e.g. real_0 imag_0, real_1 imag_1, for the fast Fourier Transform method + private double[] fftCorr = null; // corresponding array to hold the data to be correlated with first data set + private double[] fftResp = null; // corresponding array to hold the response to be convolved with first data set + private boolean fftDataSet = false; // if true - the fftData array has been filled, if false - it has not. + + private double[] fftDataWindow = null; // array holding fftData array elements multiplied by the windowing weights + private double[] fftCorrWindow = null; // corresponding array to hold the data to be correlated with first data set + + private int windowOption = 0; // Window Option + // = 0; no windowing applied (default) - equivalent to option = 1 + // = 1; Rectangular (square, box-car) + // = 2; Bartlett (triangular) + // = 3; Welch + // = 4; Hann (Hanning) + // = 5; Hamming + // = 6; Kaiser + // = 7; Gaussian + // all window names + private String[] windowNames = {"no windowing applied", "Rectangular (square, box-car)", "Bartlett (triangular)", "Welch", "Hann (Hanning)", "Hamming", "Kaiser", "Gaussian"}; + private String windowName = windowNames[0]; // current window name + private double kaiserAlpha = 2.0D; // Kaiser window constant, alpha + private double gaussianAlpha = 2.5D; // Gaussian window constant, alpha + private double[] weights = null; // windowing weights + private boolean windowSet = false; // = true when a windowing option has been chosen, otherwise = false + private boolean windowApplied = false; // = true when data has been multiplied by windowing weights, otherwise = false + private double sumOfSquaredWeights = 0.0D; // Sum of the windowing weights + + private Complex[] transformedDataComplex = null; // transformed data set of Complex numbers + private double[] transformedDataFft = null; // transformed data set of double adjacent real and imaginary parts + private boolean fftDone = false; // = false - basicFft has not been called + // = true - basicFft has been called + + private double[][] powerSpectrumEstimate = null; // first row - array to hold frequencies + // second row - array to hold estimated power density (psd) spectrum + private boolean powSpecDone = false; // = false - PowerSpectrum has not been called + // = true - PowerSpectrum has been called + private int psdNumberOfPoints = 0; // Number of points in the estimated power spectrum + + private int segmentNumber = 1; // Number of segments into which the data has been split + private int segmentLength = 0; // Number of of data points in a segment + private boolean overlap = false; // Data segment overlap option + // = true; overlap by half segment length - smallest spectral variance per data point + // good where data already recorded and data reduction is after the process + // = false; no overlap - smallest spectral variance per conputer operation + // good for real time data collection where data reduction is computer limited + private boolean segNumSet = false; // true if segment number has been set + private boolean segLenSet = false; // true of segment length has been set + + private double deltaT = 1.0D; // Sampling period (needed only for true graphical output) + private boolean deltaTset = false; // true if sampling period has been set + + private double[][] correlationArray = null; // first row - array to hold time lags + // second row - correlation between fftDataWindow and fftCorrWindow + private boolean correlateDone = false; // = false - correlation has not been called + // = true - correlation has been called + + private int numberOfWarnings = 9; // Number of warnings + private boolean[] warning = new boolean[numberOfWarnings]; // warnings - if warning[x] = true warningText[x] is printed + + private int plotLineOption = 0; // PlotPowerSpectrum line option + // = 0 points linked by straight line [default option] + // = 1 cubic spline interpolation + // = 2 no line - only points + + private int plotPointOption = 0; // PlotPowerSpectrum point option + // = 0 no point symbols [default option] + // = 1 filled circles + + private double[][] timeFrequency = null; // matrix of time against frequency mean square powers from shoert time FT + // first row = blank cell followed by time vector + // first column = blank cell followed by frequency vector + // each cell is then the mean square amplitude at that frequency and time + private boolean shortTimeDone = false; // = true when short time Fourier Transform has been performed + private int numShortFreq = 0; // number of frequency points in short time Fourier transform + private int numShortTimes = 0; // number of time points in short time Fourier transform + private String shortTitle = " "; // Short Time Fourier Transform graph title + + // constructors + // No initialisation of the data variables + public FourierTransform(){ + for(int i=0; i<numberOfWarnings; i++) warning[i] = false; + + } + + // constuctor entering a data array of real numbers + public FourierTransform(double[] realData){ + this.originalDataLength = realData.length; + this.fftDataLength = FourierTransform.nextPowerOfTwo(this.originalDataLength); + this.complexData = Complex.oneDarray(this.fftDataLength); + for(int i=0; i<this.originalDataLength; i++){ + this.complexData[i].setReal(realData[i]); + this.complexData[i].setImag(0.0D); + } + for(int i=this.originalDataLength; i<this.fftDataLength; i++)this.complexData[i].reset(0.0D, 0.0D); + this.complexDataSet = true; + + this.fftData = new double[2*this.fftDataLength]; + int j = 0; + for(int i=0; i<this.fftDataLength; i++){ + this.fftData[j] = complexData[i].getReal(); + j++; + this.fftData[j] = 0.0D; + j++; + } + this.fftDataSet = true; + + this.fftDataWindow = new double[2*this.fftDataLength]; + this.weights = new double[this.fftDataLength]; + this.sumOfSquaredWeights = windowData(this.fftData, this.fftDataWindow, this.weights); + + this.transformedDataFft = new double[2*this.fftDataLength]; + this.transformedDataComplex = Complex.oneDarray(this.fftDataLength); + this.segmentLength = this.fftDataLength; + + for(int i=0; i<numberOfWarnings; i++) warning[i] = false; + } + + // constuctor entering a data array of complex numbers + public FourierTransform(Complex[] data){ + this.originalDataLength = data.length; + this.fftDataLength = FourierTransform.nextPowerOfTwo(this.originalDataLength); + this.complexData = Complex.oneDarray(this.fftDataLength); + for(int i=0; i<this.originalDataLength; i++){ + this.complexData[i] = data[i].copy(); + } + for(int i=this.originalDataLength; i<this.fftDataLength; i++)this.complexData[i].reset(0.0D, 0.0D); + this.complexDataSet = true; + + this.fftData = new double[2*this.fftDataLength]; + int j = 0; + for(int i=0; i<this.fftDataLength; i++){ + this.fftData[j] = complexData[i].getReal(); + j++; + this.fftData[j] = complexData[i].getImag(); + j++; + } + this.fftDataSet = true; + + this.fftDataWindow = new double[2*this.fftDataLength]; + this.weights = new double[this.fftDataLength]; + this.sumOfSquaredWeights = windowData(this.fftData, this.fftDataWindow, this.weights); + + this.transformedDataFft = new double[2*this.fftDataLength]; + this.transformedDataComplex = Complex.oneDarray(this.fftDataLength); + this.segmentLength = this.fftDataLength; + + for(int i=0; i<numberOfWarnings; i++) warning[i] = false; + } + + // Enter a data array of real numbers + public void setData(double[] realData){ + this.originalDataLength = realData.length; + this.fftDataLength = FourierTransform.nextPowerOfTwo(this.originalDataLength); + this.complexData = Complex.oneDarray(this.fftDataLength); + for(int i=0; i<this.originalDataLength; i++){ + this.complexData[i].setReal(realData[i]); + this.complexData[i].setImag(0.0D); + } + for(int i=this.originalDataLength; i<this.fftDataLength; i++)this.complexData[i].reset(0.0D, 0.0D); + this.complexDataSet = true; + + this.fftData = new double[2*this.fftDataLength]; + int j = 0; + for(int i=0; i<this.fftDataLength; i++){ + this.fftData[j] = complexData[i].getReal(); + j++; + this.fftData[j] = 0.0D; + j++; + } + this.fftDataSet = true; + + this.fftDataWindow = new double[2*this.fftDataLength]; + this.weights = new double[this.fftDataLength]; + this.sumOfSquaredWeights = windowData(this.fftData, this.fftDataWindow, this.weights); + + this.transformedDataFft = new double[2*this.fftDataLength]; + this.transformedDataComplex = Complex.oneDarray(this.fftDataLength); + + if(this.segNumSet){ + this.setSegmentNumber(this.segmentNumber); + } + else{ + if(this.segLenSet){ + this.setSegmentLength(this.segmentLength); + } + else{ + this.segmentLength = this.fftDataLength; + } + } + } + + // Enter a data array of complex numbers + public void setData(Complex[] data){ + this.originalDataLength = data.length; + this.fftDataLength = FourierTransform.nextPowerOfTwo(this.originalDataLength); + this.complexData = Complex.oneDarray(this.fftDataLength); + for(int i=0; i<this.originalDataLength; i++){ + this.complexData[i] = data[i].copy(); + } + for(int i=this.originalDataLength; i<this.fftDataLength; i++)this.complexData[i].reset(0.0D, 0.0D); + this.complexDataSet = true; + + this.fftData = new double[2*this.fftDataLength]; + int j = 0; + for(int i=0; i<this.fftDataLength; i++){ + this.fftData[j] = complexData[i].getReal(); + j++; + this.fftData[j] = complexData[i].getImag(); + j++; + } + this.fftDataSet = true; + + this.fftDataWindow = new double[2*this.fftDataLength]; + this.weights = new double[this.fftDataLength]; + this.sumOfSquaredWeights = windowData(this.fftData, this.fftDataWindow, this.weights); + + this.transformedDataFft = new double[2*this.fftDataLength]; + this.transformedDataComplex = Complex.oneDarray(this.fftDataLength); + + if(this.segNumSet){ + this.setSegmentNumber(this.segmentNumber); + } + else{ + if(this.segLenSet){ + this.setSegmentLength(this.segmentLength); + } + else{ + this.segmentLength = this.fftDataLength; + } + } + } + + // Enter a data array of adjacent alternating real and imaginary parts for fft method, fastFourierTransform + public void setFftData(double[] fftdata){ + if(fftdata.length % 2 != 0)throw new IllegalArgumentException("data length must be an even number"); + + this.originalDataLength = fftdata.length/2; + this.fftDataLength = FourierTransform.nextPowerOfTwo(this.originalDataLength); + this.fftData = new double[2*this.fftDataLength]; + for(int i=0; i<2*this.originalDataLength; i++)this.fftData[i] = fftdata[i]; + for(int i=2*this.originalDataLength; i<2*this.fftDataLength; i++)this.fftData[i] = 0.0D; + this.fftDataSet = true; + + this.complexData = Complex.oneDarray(this.fftDataLength); + int j = -1; + for(int i=0; i<this.fftDataLength; i++){ + this.complexData[i].setReal(this.fftData[++j]); + this.complexData[i].setImag(this.fftData[++j]); + } + this.complexDataSet = true; + + this.fftDataWindow = new double[2*this.fftDataLength]; + this.weights = new double[this.fftDataLength]; + this.sumOfSquaredWeights = windowData(this.fftData, this.fftDataWindow, this.weights); + + this.transformedDataFft = new double[2*this.fftDataLength]; + this.transformedDataComplex = Complex.oneDarray(this.fftDataLength); + + if(this.segNumSet){ + this.setSegmentNumber(this.segmentNumber); + } + else{ + if(this.segLenSet){ + this.setSegmentLength(this.segmentLength); + } + else{ + this.segmentLength = this.fftDataLength; + } + } + } + + // Get the input data array as Complex + public Complex[] getComplexInputData(){ + if(!this.complexDataSet){ + System.out.println("complex data set not entered or calculated - null returned"); + } + return this.complexData; + } + + // Get the input data array as adjacent real and imaginary pairs + public double[] getAlternateInputData(){ + if(!this.fftDataSet){ + System.out.println("fft data set not entered or calculted - null returned"); + } + return this.fftData; + } + + // Get the windowed input data array as windowed adjacent real and imaginary pairs + public double[] getAlternateWindowedInputData(){ + if(!this.fftDataSet){ + System.out.println("fft data set not entered or calculted - null returned"); + } + if(!this.fftDataSet){ + System.out.println("fft data set not entered or calculted - null returned"); + } + if(!this.windowApplied){ + System.out.println("fft data set has not been multiplied by windowing weights"); + } + return this.fftDataWindow; + } + + // get the original number of data points + public int getOriginalDataLength(){ + return this.originalDataLength; + } + + // get the actual number of data points + public int getUsedDataLength(){ + return this.fftDataLength; + } + + // Set a samplimg period + public void setDeltaT(double deltaT){ + this.deltaT = deltaT; + this.deltaTset = true; + } + + // Get the samplimg period + public double getDeltaT(){ + double ret = 0.0D; + if(this.deltaTset){ + ret = this.deltaT; + } + else{ + System.out.println("detaT has not been set - zero returned"); + } + return ret; + } + + // Set a Rectangular window option + public void setRectangular(){ + this.windowOption = 1; + this.windowSet = true; + if(fftDataSet){ + this.sumOfSquaredWeights = this.windowData(this.fftData, this.fftDataWindow, this.weights); + this.windowApplied = true; + } + } + + // Set a Bartlett window option + public void setBartlett(){ + this.windowOption = 2; + this.windowSet = true; + if(fftDataSet){ + this.sumOfSquaredWeights = this.windowData(this.fftData, this.fftDataWindow, this.weights); + this.windowApplied = true; + } + } + + // Set a Welch window option + public void setWelch(){ + this.windowOption = 3; + this.windowSet = true; + if(fftDataSet){ + this.sumOfSquaredWeights = this.windowData(this.fftData, this.fftDataWindow, this.weights); + this.windowApplied = true; + } + } + + // Set a Hann window option + public void setHann(){ + this.windowOption = 4; + this.windowSet = true; + if(fftDataSet){ + this.sumOfSquaredWeights = this.windowData(this.fftData, this.fftDataWindow, this.weights); + this.windowApplied = true; + } + } + + // Set a Hamming window option + public void setHamming(){ + this.windowOption = 5; + this.windowSet = true; + if(fftDataSet){ + this.sumOfSquaredWeights = this.windowData(this.fftData, this.fftDataWindow, this.weights); + this.windowApplied = true; + } + } + + // Set a Kaiser window option + public void setKaiser(double alpha){ + this.kaiserAlpha = alpha; + this.windowOption = 6; + this.windowSet = true; + if(fftDataSet){ + this.sumOfSquaredWeights = this.windowData(this.fftData, this.fftDataWindow, this.weights); + this.windowApplied = true; + } + } + + // Set a Kaiser window option + // default option for alpha + public void setKaiser(){ + this.windowOption = 6; + this.windowSet = true; + if(fftDataSet){ + this.sumOfSquaredWeights = this.windowData(this.fftData, this.fftDataWindow, this.weights); + this.windowApplied = true; + } + } + + // Set a Gaussian window option + public void setGaussian(double alpha){ + if(alpha<2.0D){ + alpha=2.0D; + System.out.println("setGaussian; alpha must be greater than or equal to 2 - alpha has been reset to 2"); + } + this.gaussianAlpha = alpha; + this.windowOption = 7; + this.windowSet = true; + if(fftDataSet){ + this.sumOfSquaredWeights = this.windowData(this.fftData, this.fftDataWindow, this.weights); + this.windowApplied = true; + } + } + + // Set a Gaussian window option + // default option for alpha + public void setGaussian(){ + this.windowOption = 7; + this.windowSet = true; + if(fftDataSet){ + this.sumOfSquaredWeights = this.windowData(this.fftData, this.fftDataWindow, this.weights); + this.windowApplied = true; + } + } + + // Remove windowing + public void removeWindow(){ + this.windowOption = 0; + this.windowSet = false; + if(fftDataSet){ + this.sumOfSquaredWeights = this.windowData(this.fftData, this.fftDataWindow, this.weights); + this.windowApplied = false; + } + } + + // Applies a window to the data + private double windowData(double[] data, double[] window, double[] weight){ + int m = data.length; + int n = m/2-1; + int j = 0; + double sum = 0.0D; + switch(this.windowOption){ + // 0. No windowing applied or remove windowing + case 0: + // 1. Rectangular + case 1: for(int i=0; i<=n; i++){ + weight[i] = 1.0D; + window[j] = data[j++]; + window[j] = data[j++]; + } + sum = n+1; + break; + // 2. Bartlett + case 2: for(int i=0; i<=n; i++){ + weight[i] = 1.0D - Math.abs((i-n/2)/n/2); + sum += weight[i]*weight[i]; + window[j] = data[j++]*weight[i]; + window[j] = data[j++]*weight[i]; + } + break; + // 3. Welch + case 3: for(int i=0; i<=n; i++){ + weight[i] = 1.0D - Fmath.square((i-n/2)/n/2); + sum += weight[i]*weight[i]; + window[j] = data[j++]*weight[i]; + window[j] = data[j++]*weight[i]; + } + break; + // 4. Hann + case 4: for(int i=0; i<=n; i++){ + weight[i] = (1.0D - Math.cos(2.0D*i*Math.PI/n))/2.0D; + sum += weight[i]*weight[i]; + window[j] = data[j++]*weight[i]; + window[j] = data[j++]*weight[i]; + } + break; + // 5. Hamming + case 5: for(int i=0; i<=n; i++){ + weight[i] = 0.54D + 0.46D*Math.cos(2.0D*i*Math.PI/n); + sum += weight[i]*weight[i]; + window[j] = data[j++]*weight[i]; + window[j] = data[j++]*weight[i]; + } + break; + // 6. Kaiser + case 6: double denom = FourierTransform.modBesselIo(Math.PI*this.kaiserAlpha); + double numer = 0.0D; + for(int i=0; i<=n; i++){ + numer = FourierTransform.modBesselIo(Math.PI*this.kaiserAlpha*Math.sqrt(1.0D-Fmath.square(2.0D*i/n-1.0D))); + weight[i] = numer/denom; + sum += weight[i]*weight[i]; + window[j] = data[j++]*weight[i]; + window[j] = data[j++]*weight[i]; + } + break; + // 6. Kaiser + case 7: for(int i=0; i<=n; i++){ + weight[i] = Math.exp(-0.5D*Fmath.square(this.gaussianAlpha*(2*i-n)/n)); + sum += weight[i]*weight[i]; + window[j] = data[j++]*weight[i]; + window[j] = data[j++]*weight[i]; + } + break; + } + return sum; + } + + // return modified Bessel Function of the zeroth order (for Kaiser window) + // after numerical Recipe's bessi0 + // - Abramowitz and Stegun coeeficients + public static double modBesselIo(double arg){ + double absArg = 0.0D; + double poly = 0.0D; + double bessel = 0.0D; + + if((absArg = Math.abs(arg)) < 3.75){ + poly = arg/3.75; + poly *= poly; + bessel = 1.0D + poly*(3.5156229D + poly*(3.08989424D + poly*(1.2067492D + poly*(0.2659732 + poly*(0.360768e-1 + poly*0.45813e-2))))); + } + else{ + bessel = (Math.exp(absArg)/Math.sqrt(absArg))*(0.39894228D + poly*(0.1328592e-1D + poly*(0.225319e-2 + poly*(-0.157565e-2 + poly*(0.916281e-2 + poly*(-0.2057706e-1 + poly*(0.2635537e-1 + poly*(-0.1647633e-1 + poly*0.392377e-2)))))))); + } + return bessel; + } + + // get window option - see above for options + public String getWindowOption(){ + String option = " "; + switch(this.windowOption){ + case 0: option = "No windowing applied"; + break; + case 1: option = "Rectangular"; + break; + case 2: option = "Bartlett"; + break; + case 3: option = "Welch"; + break; + case 4: option = "Hann"; + break; + case 5: option = "Hamming"; + break; + case 6: option = "Kaiser"; + break; + case 7: option = "Gaussian"; + break; + } + return option; + } + + // Get the windowing weights + public double[] getWeights(){ + return this.weights; + } + + // set the number of segments + public void setSegmentNumber(int sNum){ + this.segmentNumber = sNum; + this.segNumSet = true; + if(this.segLenSet)this.segLenSet=false; + } + + // set the segment length + public void setSegmentLength(int sLen){ + this.segmentLength = sLen; + this.segLenSet = true; + if(this.segNumSet)this.segNumSet=false; + } + + // check and set up the segments + private void checkSegmentDetails(){ + if(!this.fftDataSet)throw new IllegalArgumentException("No fft data has been entered or calculated"); + if(this.fftDataLength<2)throw new IllegalArgumentException("More than one point, MANY MORE, are needed"); + + // check if data number is even + if(this.fftDataLength % 2 != 0){ + System.out.println("Number of data points must be an even number"); + System.out.println("last point deleted"); + this.fftDataLength -= 1; + this.dataAltered = true; + this.warning[0] = true; + } + + // check segmentation with no overlap + if(this.segNumSet && !this.overlap){ + if(this.fftDataLength % this.segmentNumber == 0){ + int segL = this.fftDataLength/this.segmentNumber; + if(FourierTransform.checkPowerOfTwo(segL)){ + this.segmentLength = segL; + this.segLenSet = true; + } + else{ + System.out.println("segment length is not an integer power of two"); + System.out.println("segment length reset to total data length, i.e. no segmentation"); + warning[1] = true; + this.segmentNumber = 1; + this.segmentLength = this.fftDataLength; + this.segLenSet = true; + } + } + else{ + System.out.println("total data length divided by the number of segments is not an integer"); + System.out.println("segment length reset to total data length, i.e. no segmentation"); + warning[2] = true; + this.segmentNumber = 1; + this.segmentLength = this.fftDataLength; + this.segLenSet = true; + } + } + + if(this.segLenSet && !this.overlap){ + if(this.fftDataLength % this.segmentLength == 0){ + if(FourierTransform.checkPowerOfTwo(this.segmentLength)){ + this.segmentNumber = this.fftDataLength/this.segmentLength; + this.segNumSet = true; + } + else{ + System.out.println("segment length is not an integer power of two"); + System.out.println("segment length reset to total data length, i.e. no segmentation"); + warning[1] = true; + this.segmentNumber = 1; + this.segmentLength = this.fftDataLength; + this.segNumSet = true; + } + } + else{ + System.out.println("total data length divided by the segment length is not an integer"); + System.out.println("segment length reset to total data length, i.e. no segmentation"); + warning[3] = true; + this.segmentNumber = 1; + this.segmentLength = this.fftDataLength; + this.segNumSet = true; + } + } + + // check segmentation with overlap + if(this.segNumSet && this.overlap){ + if(this.fftDataLength % (this.segmentNumber+1) == 0){ + int segL = 2*this.fftDataLength/(this.segmentNumber+1); + if(FourierTransform.checkPowerOfTwo(segL)){ + this.segmentLength = segL; + this.segLenSet = true; + } + else{ + System.out.println("segment length is not an integer power of two"); + System.out.println("segment length reset to total data length, i.e. no segmentation"); + warning[1] = true; + this.segmentNumber = 1; + this.segmentLength = this.fftDataLength; + this.segLenSet = true; + this.overlap = false; + } + } + else{ + System.out.println("total data length divided by the number of segments plus one is not an integer"); + System.out.println("segment length reset to total data length, i.e. no segmentation"); + warning[4] = true; + this.segmentNumber = 1; + this.segmentLength = this.fftDataLength; + this.segLenSet = true; + this.overlap = false; + } + } + + if(this.segLenSet && this.overlap){ + if((2*this.fftDataLength) % this.segmentLength == 0){ + if(FourierTransform.checkPowerOfTwo(this.segmentLength)){ + this.segmentNumber = (2*this.fftDataLength)/this.segmentLength - 1; + this.segNumSet = true; + } + else{ + System.out.println("segment length is not an integer power of two"); + System.out.println("segment length reset to total data length, i.e. no segmentation"); + warning[1] = true; + this.segmentNumber = 1; + this.segmentLength = this.fftDataLength; + this.segNumSet = true; + this.overlap = false; + } + } + else{ + System.out.println("twice the total data length divided by the segment length is not an integer"); + System.out.println("segment length reset to total data length, i.e. no segmentation"); + warning[5] = true; + this.segmentNumber = 1; + this.segmentLength = this.fftDataLength; + this.segNumSet = true; + this.overlap = false; + } + } + + if(!this.segNumSet && !this.segLenSet){ + this.segmentNumber = 1; + this.segNumSet = true; + this.overlap = false; + } + + if(this.overlap && this.segmentNumber<2){ + System.out.println("Overlap is not possible with less than two segments."); + System.out.println("Overlap option has been reset to 'no overlap' i.e. to false."); + this.overlap = false; + this.segmentNumber = 1; + this.segNumSet = true; + warning[6] = true; + } + + // check no segmentation option + int segLno = 0; + int segNno = 0; + int segLov = 0; + int segNov = 0; + + if(this.segmentNumber==1){ + // check if data number is a power of two + if(!FourierTransform.checkPowerOfTwo(this.fftDataLength)){ + boolean test0 = true; + boolean test1 = true; + boolean test2 = true; + int newL = 0; + int ii=2; + // not a power of two - check segmentation options + // no overlap option + while(test0){ + newL = this.fftDataLength/ii; + if(FourierTransform.checkPowerOfTwo(newL) && (this.fftDataLength % ii)==0){ + test0 = false; + segLno = newL; + segNno = ii; + } + else{ + if(newL<2){ + test1 = false; + test0 = false; + } + else{ + ii++; + } + } + } + test0 = true; + ii = 2; + // overlap option + while(test0){ + newL = 2*(this.fftDataLength/(ii+1)); + if(FourierTransform.checkPowerOfTwo(newL) && (this.fftDataLength % (ii+1))==0){ + test0 = false; + segLov = newL; + segNov = ii; + } + else{ + if(newL<2){ + test2 = false; + test0 = false; + } + else{ + ii++; + } + } + } + // compare overlap and no overlap options + boolean setSegment = true; + int segL = 0; + int segN = 0; + boolean ovrlp = false; + if(test1){ + if(test2){ + if(segLov>segLno){ + segL = segLov; + segN = segNov; + ovrlp = true; + } + else{ + segL = segLno; + segN = segNno; + ovrlp = false; + } + } + else{ + segL = segLno; + segN = segNno; + ovrlp = false; + } + } + else{ + if(test2){ + segL = segLov; + segN = segNov; + ovrlp = true; + } + else{ + setSegment = false; + } + } + + // compare segmentation and zero padding + if(setSegment && (this.originalDataLength-segL <= this.fftDataLength - this.originalDataLength)){ + System.out.println("Data length is not an integer power of two"); + System.out.println("Data cannot be transformed as a single segment"); + System.out.print("The data has been split into " + segN+ " segments of length " + segL); + if(ovrlp){ + System.out.println(" with 50% overlap"); + } + else{ + System.out.println(" with no overlap"); + } + this.segmentLength = segL; + this.segmentNumber = segN; + this.overlap = ovrlp; + this.warning[7] = true; + } + else{ + System.out.println("Data length is not an integer power of two"); + if(this.dataAltered){ + System.out.println("Deleted point has been restored and the data has been padded with zeros to give a power of two length"); + this.warning[0] = false; + } + else{ + System.out.println("Data has been padded with zeros to give a power of two length"); + } + this.fftDataLength = this.fftDataLength; + this.warning[8] = true; + } + } + } + } + + private void printWarnings(FileOutput fout){ + if(warning[0]){ + fout.println("WARNING!"); + fout.println("Number of data points must be an even number"); + fout.println("The last point was deleted"); + fout.println(); + } + + if(warning[1]){ + fout.println("WARNING!"); + fout.println("Segment length was not an integer power of two"); + fout.println("Segment length was reset to total data length, i.e. no segmentation"); + fout.println(); + } + + if(warning[2]){ + fout.println("WARNING!"); + fout.println("Total data length divided by the number of segments was not an integer"); + fout.println("Segment length was reset to total data length, i.e. no segmentation"); + fout.println(); + } + + if(warning[3]){ + fout.println("WARNING!"); + fout.println("Total data length divided by the segment length was not an integer"); + fout.println("Segment length was reset to total data length, i.e. no segmentation"); + fout.println(); + } + + if(warning[4]){ + fout.println("WARNING!"); + fout.println("Total data length divided by the number of segments plus one was not an integer"); + fout.println("Segment length was reset to total data length, i.e. no segmentation"); + fout.println(); + } + + if(warning[5]){ + fout.println("WARNING!"); + fout.println("Twice the total data length divided by the segment length was not an integer"); + fout.println("Segment length was reset to total data length, i.e. no segmentation"); + fout.println(); + } + + if(warning[6]){ + fout.println("WARNING!"); + fout.println("Overlap is not possible with less than two segments"); + fout.println("Overlap option has been reset to 'no overlap' i.e. to false"); + fout.println(); + } + + if(warning[7]){ + fout.println("WARNING!"); + fout.println("Data length was not an integer power of two"); + fout.println("The data could not be transformed as a single segment"); + fout.print("The data has been split into " + this.segmentNumber+ " segment/s of length " + this.segmentLength); + if(this.overlap){ + fout.println(" with 50% overlap"); + } + else{ + fout.println(" with no overlap"); + } + fout.println(); + } + + if(warning[8]){ + fout.println("WARNING!"); + fout.println("Data length was not an integer power of two"); + fout.println("Data has been padded with " + (this.fftDataLength-this.originalDataLength) + " zeros to give an integer power of two length"); + fout.println(); + } + } + + // get the number of segments + public int getSegmentNumber(){ + return this.segmentNumber; + } + + // get the segment length + public int getSegmentLength(){ + return this.segmentLength; + } + + // set overlap option - see above (head of program comment lines) for option description + public void setOverlapOption(boolean overlapOpt){ + boolean old = this.overlap; + this.overlap = overlapOpt; + if(old != this.overlap){ + if(this.fftDataSet){ + this.setSegmentNumber(this.segmentNumber); + } + } + } + + // get overlap option - see above for options + public boolean getOverlapOption(){ + return this.overlap; + } + + // calculate the number of data points given the: + // segment length (segLen), number of segments (segNum) + // and the overlap option (overlap: true - overlap, false - no overlap) + public static int calcDataLength(boolean overlap, int segLen, int segNum){ + if(overlap){ + return (segNum+1)*segLen/2; + } + else{ + return segNum*segLen; + } + } + + // Method for performing a Fast Fourier Transform + public void transform(){ + + // set up data array + int isign = 1; + if(!this.fftDataSet)throw new IllegalArgumentException("No data has been entered for the Fast Fourier Transform"); + if(this.originalDataLength!=this.fftDataLength){ + System.out.println("Fast Fourier Transform data length ," + this.originalDataLength + ", is not an integer power of two"); + System.out.println("WARNING!!! Data has been padded with zeros to fill to nearest integer power of two length " + this.fftDataLength); + } + + // Perform fft + double[] hold = new double[this.fftDataLength*2]; + for(int i=0; i<this.fftDataLength*2; i++)hold[i] = this.fftDataWindow[i]; + basicFft(hold, this.fftDataLength, isign); + for(int i=0; i<this.fftDataLength*2; i++)this.transformedDataFft[i] = hold[i]; + + // fill transformed data arrays + for(int i=0; i<this.fftDataLength; i++){ + this.transformedDataComplex[i].reset(this.transformedDataFft[2*i], this.transformedDataFft[2*i+1]); + } + } + + // Method for performing an inverse Fast Fourier Transform + public void inverse(){ + + // set up data array + int isign = -1; + if(!this.fftDataSet)throw new IllegalArgumentException("No data has been entered for the inverse Fast Fourier Transform"); + if(this.originalDataLength!=this.fftDataLength){ + System.out.println("Fast Fourier Transform data length ," + this.originalDataLength + ", is not an integer power of two"); + System.out.println("WARNING!!! Data has been padded with zeros to fill to nearest integer power of two length " + this.fftDataLength); + } + + // Perform inverse fft + double[] hold = new double[this.fftDataLength*2]; + for(int i=0; i<this.fftDataLength*2; i++)hold[i] = this.fftDataWindow[i]; + basicFft(hold, this.fftDataLength, isign); + + for(int i=0; i<this.fftDataLength*2; i++)this.transformedDataFft[i] = hold[i]/this.fftDataLength; + + // fill transformed data arrays + for(int i=0; i<this.fftDataLength; i++){ + this.transformedDataComplex[i].reset(this.transformedDataFft[2*i], this.transformedDataFft[2*i+1]); + } + } + + // Base method for performing a Fast Fourier Transform + // Based on the Numerical Recipes procedure four1 + // If isign is set to +1 this method replaces fftData[0 to 2*nn-1] by its discrete Fourier Transform + // If isign is set to -1 this method replaces fftData[0 to 2*nn-1] by nn times its inverse discrete Fourier Transform + // nn MUST be an integer power of 2. This is not checked for in this method, fastFourierTransform(...), for speed. + // If not checked for by the calling method, e.g. powerSpectrum(...) does, the method checkPowerOfTwo() may be used to check this. + // The real and imaginary parts of the data are stored adjacently + // i.e. fftData[0] holds the real part, fftData[1] holds the corresponding imaginary part of a data point + // data array and data array length over 2 (nn) transferred as arguments + // result NOT returned to this.transformedDataFft + // Based on the Numerical Recipes procedure four1 + public void basicFft(double[] data, int nn, int isign) + { + double dtemp = 0.0D, wtemp = 0.0D, tempr = 0.0D, tempi = 0.0D; + double theta = 0.0D, wr = 0.0D, wpr = 0.0D, wpi = 0.0D, wi = 0.0D; + int istep = 0, m = 0, mmax = 0; + int n = nn << 1; + int j = 1; + int jj = 0; + for (int i=1;i<n;i+=2) { + jj = j-1; + if (j > i) { + int ii = i-1; + dtemp = data[jj]; + data[jj] = data[ii]; + data[ii] = dtemp; + dtemp = data[jj+1]; + data[jj+1] = data[ii+1]; + data[ii+1] = dtemp; + } + m = n >> 1; + while (m >= 2 && j > m) { + j -= m; + m >>= 1; + } + j += m; + } + mmax=2; + while (n > mmax) { + istep=mmax << 1; + theta=isign*(6.28318530717959D/mmax); + wtemp=Math.sin(0.5D*theta); + wpr = -2.0D*wtemp*wtemp; + wpi=Math.sin(theta); + wr=1.0D; + wi=0.0D; + for (m=1;m<mmax;m+=2L) { + for (int i=m;i<=n;i+=istep) { + int ii = i - 1; + jj=ii+mmax; + tempr=wr*data[jj]-wi*data[jj+1]; + tempi=wr*data[jj+1]+wi*data[jj]; + data[jj]=data[ii]-tempr; + data[jj+1]=data[ii+1]-tempi; + data[ii] += tempr; + data[ii+1] += tempi; + } + wr=(wtemp=wr)*wpr-wi*wpi+wr; + wi=wi*wpr+wtemp*wpi+wi; + } + mmax=istep; + } + } + + // Get the transformed data as Complex + public Complex[] getTransformedDataAsComplex(){ + return this.transformedDataComplex; + } + + // Get the transformed data array as adjacent real and imaginary pairs + public double[] getTransformedDataAsAlternate(){ + return this.transformedDataFft; + } + + // Performs and returns results a fft power spectrum density (psd) estimation + // of unsegmented, segmented or segemented and overlapped data + // data in array fftDataWindow + public double[][] powerSpectrum(){ + + this.checkSegmentDetails(); + + this.psdNumberOfPoints = this.segmentLength/2; + this.powerSpectrumEstimate = new double[2][this.psdNumberOfPoints]; + + if(!overlap && this.segmentNumber<2){ + // Unsegmented and non-overlapped data + + // set up data array + int isign = 1; + if(!this.fftDataSet)throw new IllegalArgumentException("No data has been entered for the Fast Fourier Transform"); + if(!FourierTransform.checkPowerOfTwo(this.fftDataLength))throw new IllegalArgumentException("Fast Fourier Transform data length ," + this.fftDataLength + ", is not an integer power of two"); + + // perform fft + double[] hold = new double[this.fftDataLength*2]; + for(int i=0; i<this.fftDataLength*2; i++)hold[i] = this.fftDataWindow[i]; + basicFft(hold, this.fftDataLength, isign); + for(int i=0; i<this.fftDataLength*2; i++)this.transformedDataFft[i] = hold[i]; + + // fill transformed data arrays + for(int i=0; i<this.fftDataLength; i++){ + this.transformedDataComplex[i].reset(this.transformedDataFft[2*i], this.transformedDataFft[2*i+1]); + } + + // obtain weighted mean square amplitudes + this.powerSpectrumEstimate[1][0] = Fmath.square(hold[0]) + Fmath.square(hold[1]); + for(int i=1; i<this.psdNumberOfPoints; i++){ + this.powerSpectrumEstimate[1][i] = Fmath.square(hold[2*i]) + Fmath.square(hold[2*i+1]) + Fmath.square(hold[2*this.segmentLength-2*i]) + Fmath.square(hold[2*this.segmentLength-2*i+1]); + } + + // Normalise + for(int i=0; i<this.psdNumberOfPoints; i++){ + this.powerSpectrumEstimate[1][i] = 2.0D*this.powerSpectrumEstimate[1][i]/(this.fftDataLength*this.sumOfSquaredWeights); + } + + // Calculate frequencies + for(int i=0; i<this.psdNumberOfPoints; i++){ + this.powerSpectrumEstimate[0][i] = (double)i/((double)this.segmentLength*this.deltaT); + } + } + else{ + // Segmented or segmented and overlapped data + this.powerSpectrumEstimate = powerSpectrumSeg(); + } + + this.powSpecDone = true; + + return this.powerSpectrumEstimate; + } + + // Performs and returns results a fft power spectrum density (psd) estimation + // of unsegmented, segmented or segemented and overlaped data + // data read in from a text file + public double[][] powerSpectrum(String fileName){ + + if(!FourierTransform.checkPowerOfTwo(this.segmentLength))throw new IllegalArgumentException("Fast Fourier Transform segment length ," + this.segmentLength + ", is not an integer power of two"); + + FileInput fin = new FileInput(fileName); + + this.psdNumberOfPoints = this.segmentLength/2; + this.powerSpectrumEstimate = new double[2][this.psdNumberOfPoints]; + this.fftDataLength = FourierTransform.calcDataLength(this.overlap, this.segmentLength, this.segmentNumber); + + if(!overlap && this.segmentNumber<2){ + // Unsegmented and non-overlapped data + + // read in data + this.fftData = new double[2*this.fftDataLength]; + int j = -1; + for(int i=0; i<this.segmentLength; i++){ + this.fftData[++j] = fin.readDouble(); + this.fftData[++j] = fin.readDouble(); + } + + this.complexData = Complex.oneDarray(this.fftDataLength); + j = -1; + for(int i=0; i<this.fftDataLength; i++){ + this.complexData[i].setReal(this.fftData[++j]); + this.complexData[i].setImag(this.fftData[++j]); + } + + this.fftDataWindow = new double[2*this.fftDataLength]; + this.sumOfSquaredWeights = this.windowData(this.fftData, this.fftDataWindow, this.weights); + + // perform fft + int isign = 1; + double[] hold = new double[this.fftDataLength*2]; + for(int i=0; i<this.fftDataLength*2; i++)hold[i] = this.fftDataWindow[i]; + basicFft(hold, this.fftDataLength, isign); + for(int i=0; i<this.fftDataLength*2; i++)this.transformedDataFft[i] = hold[i]; + + // fill transformed data arrays + for(int i=0; i<this.fftDataLength; i++){ + this.transformedDataComplex[i].reset(this.transformedDataFft[2*i], this.transformedDataFft[2*i+1]); + } + + // obtain weighted mean square amplitudes + this.powerSpectrumEstimate[1][0] = Fmath.square(hold[0]) + Fmath.square(hold[1]); + for(int i=1; i<this.psdNumberOfPoints; i++){ + this.powerSpectrumEstimate[1][i] = Fmath.square(hold[2*i]) + Fmath.square(hold[2*i+1]) + Fmath.square(hold[2*this.segmentLength-2*i]) + Fmath.square(hold[2*this.segmentLength-2*i+1]); + } + + // Normalise + for(int i=0; i<this.psdNumberOfPoints; i++){ + this.powerSpectrumEstimate[1][i] = 2.0D*this.powerSpectrumEstimate[1][i]/(this.fftDataLength*this.sumOfSquaredWeights); + } + + // Calculate frequencies + for(int i=0; i<this.psdNumberOfPoints; i++){ + this.powerSpectrumEstimate[0][i] = (double)i/((double)this.segmentLength*this.deltaT); + } + + } + else{ + // Segmented or segmented and overlapped data + this.powerSpectrumEstimate = powerSpectrumSeg(fin); + } + + this.powSpecDone = true; + + return this.powerSpectrumEstimate; + } + + + // Performs and returns results a fft power spectrum density (psd) estimation of segmented or segemented and overlaped data + // Data in fftDataWindow array + // Private method for PowerSpectrum (see above) + private double[][] powerSpectrumSeg(){ + + // set up segment details + int segmentStartIndex = 0; + int segmentStartIncrement = this.segmentLength; + if(this.overlap)segmentStartIncrement /= 2; + double[] data = new double[2*this.segmentLength]; // holds data and transformed data for working segment + this.psdNumberOfPoints = this.segmentLength/2; // number of PSD points + double[] segPSD = new double[this.psdNumberOfPoints]; // holds psd for working segment + double[][] avePSD = new double[2][this.psdNumberOfPoints]; // first row - frequencies + // second row - accumaltes psd for averaging and then the averaged psd + + // initialis psd array and transform option + for(int j=0; j<this.psdNumberOfPoints; j++)avePSD[1][j] = 0.0D; + int isign = 1; + + // loop through segments + for(int i=1; i<=this.segmentNumber; i++){ + + // collect segment data + for(int j=0; j<2*this.segmentLength; j++)data[j] = this.fftData[segmentStartIndex+j]; + + // window data + if(i==1){ + this.sumOfSquaredWeights = this.windowData(data, data, this.weights); + } + else{ + int k=0; + for(int j=0; j<this.segmentLength; j++){ + data[k] = data[k]*this.weights[j]; + data[++k] = data[k]*this.weights[j]; + ++k; + } + } + + // perform fft on windowed segment + basicFft(data, this.segmentLength, isign); + + // obtain weighted mean square amplitudes + segPSD[0] = Fmath.square(data[0]) + Fmath.square(data[1]); + for(int j=1; j<this.psdNumberOfPoints; j++){ + segPSD[j] = Fmath.square(data[2*j]) + Fmath.square(data[2*j+1]) + Fmath.square(data[2*this.segmentLength-2*j]) + Fmath.square(data[2*this.segmentLength-2*j+1]); + } + + // Normalise + for(int j=0; j<this.psdNumberOfPoints; j++){ + segPSD[j] = 2.0D*segPSD[j]/(this.segmentLength*this.sumOfSquaredWeights); + } + + // accumalate for averaging + for(int j=0; j<this.psdNumberOfPoints; j++)avePSD[1][j] += segPSD[j]; + + // increment segment start index + segmentStartIndex += segmentStartIncrement; + } + + // average all segments + for(int j=0; j<this.psdNumberOfPoints; j++)avePSD[1][j] /= this.segmentNumber; + + // Calculate frequencies + for(int i=0; i<this.psdNumberOfPoints; i++){ + avePSD[0][i] = (double)i/((double)this.segmentLength*this.deltaT); + } + + return avePSD; + } + + // Performs and returns results a fft power spectrum density (psd) estimation of segmented or segemented and overlaped data + // Data read in from a text file + // Private method for PowerSpectrum(fileName) (see above) + private double[][] powerSpectrumSeg(FileInput fin){ + + // set up segment details + double[] data = new double[2*this.segmentLength]; // holds data and transformed data for working segment + this.weights = new double[this.segmentLength]; // windowing weights for segment + double[] hold = new double[2*this.segmentLength]; // working array + this.psdNumberOfPoints = this.segmentLength/2; // number of PSD points + double[] segPSD = new double[this.psdNumberOfPoints]; // holds psd for working segment + double[][] avePSD = new double[2][this.psdNumberOfPoints]; // first row - frequencies + // second row - accumaltes psd for averaging and then the averaged psd + + // initialise psd array and fft option + for(int j=0; j<this.psdNumberOfPoints; j++)avePSD[1][j] = 0.0D; + int isign = 1; + + // calculate window weights + this.sumOfSquaredWeights = this.windowData(hold, hold, this.weights); + + if(this.overlap){ + // overlapping segments + + // read in first half segment + for(int j=0; j<this.segmentLength; j++){ + data[j] = fin.readDouble(); + } + + // loop through segments + for(int i=1; i<=this.segmentNumber; i++){ + + // read in next half segment + for(int j=0; j<this.segmentLength; j++){ + data[j+this.segmentLength] = fin.readDouble(); + } + + // window data + int k=-1; + for(int j=0; j<this.segmentLength; j++){ + data[++k] = data[k]*this.weights[j]; + data[++k] = data[k]*this.weights[j]; + } + + // perform fft on windowed segment + basicFft(data, this.segmentLength, isign); + + // obtain weighted mean square amplitudes + segPSD[0] = Fmath.square(data[0]) + Fmath.square(data[1]); + for(int j=1; j<this.psdNumberOfPoints; j++){ + segPSD[j] = Fmath.square(data[2*j]) + Fmath.square(data[2*j+1]) + Fmath.square(data[2*this.segmentLength-2*j]) + Fmath.square(data[2*this.segmentLength-2*j+1]); + } + + // Normalise + for(int j=0; j<this.psdNumberOfPoints; j++){ + segPSD[j] = 2.0D*segPSD[j]/(this.segmentLength*this.sumOfSquaredWeights); + } + + // accumalate for averaging + for(int j=0; j<this.psdNumberOfPoints; j++)avePSD[1][j] += segPSD[j]; + + // shift half segment + for(int j=0; j<this.segmentLength; j++){ + data[j] = data[j+this.segmentLength]; + } + } + } + else{ + // No overlap + + // loop through segments + for(int i=1; i<=this.segmentNumber; i++){ + + // read in segment data + for(int j=0; j<2*this.segmentLength; j++){ + data[j] = fin.readDouble(); + } + + // window data + int k=-1; + for(int j=0; j<this.segmentLength; j++){ + data[++k] = data[k]*this.weights[j]; + data[++k] = data[k]*this.weights[j]; + } + + // perform fft on windowed segment + basicFft(data, this.segmentLength, isign); + + // obtain weighted mean square amplitudes + segPSD[0] = Fmath.square(data[0]) + Fmath.square(data[1]); + for(int j=1; j<this.psdNumberOfPoints; j++){ + segPSD[j] = Fmath.square(data[2*j]) + Fmath.square(data[2*j+1]) + Fmath.square(data[2*this.segmentLength-2*j]) + Fmath.square(data[2*this.segmentLength-2*j+1]); + } + + // Normalise + for(int j=1; j<this.psdNumberOfPoints; j++){ + segPSD[j] = 2.0D*segPSD[j]/(this.segmentLength*this.sumOfSquaredWeights); + } + + // accumalate for averaging + for(int j=0; j<this.psdNumberOfPoints; j++)avePSD[1][j] += segPSD[j]; + } + } + + // average all segments + for(int j=0; j<this.psdNumberOfPoints; j++)avePSD[1][j] /= this.segmentNumber; + + // Calculate frequencies + for(int i=0; i<this.psdNumberOfPoints; i++){ + avePSD[0][i] = (double)i/((double)this.segmentLength*this.deltaT); + } + + return avePSD; + } + + // Get the power spectrum + public double[][] getpowerSpectrumEstimate(){ + if(!this.powSpecDone)System.out.println("getpowerSpectrumEstimate - powerSpectrum has not been called - null returned"); + return this.powerSpectrumEstimate; + } + + + // get the number of power spectrum frequency points + public int getNumberOfPsdPoints(){ + return this.psdNumberOfPoints; + } + + // Print the power spectrum to a text file + // default file name + public void printPowerSpectrum(){ + String filename = "FourierTransformPSD.txt"; + printPowerSpectrum(filename); + } + + // Print the power spectrum to a text file + public void printPowerSpectrum(String filename){ + if(!this.powSpecDone)this.powerSpectrum(); + + FileOutput fout = new FileOutput(filename); + fout.println("Power Spectrum Density Estimate Output File from FourierTransform"); + fout.dateAndTimeln(filename); + String title = "Window: "+this.windowNames[this.windowOption]; + if(this.windowOption==6)title += ", alpha = "+this.kaiserAlpha; + if(this.windowOption==7)title += ", alpha = "+this.gaussianAlpha; + fout.println(title); + fout.printtab("Number of segments = "); + fout.println(this.segmentNumber); + fout.printtab("Segment length = "); + fout.println(this.segmentLength); + if(this.segmentNumber>1){ + if(this.overlap){ + fout.printtab("Segments overlap by 50%"); + } + else{ + fout.printtab("Segments do not overlap"); + } + } + + fout.println(); + printWarnings(fout); + + fout.printtab("Frequency"); + fout.println("Mean Square"); + fout.printtab("(cycles per"); + fout.println("Amplitude"); + if(this.deltaTset){ + fout.printtab("unit time)"); + } + else{ + fout.printtab("gridpoint)"); + } + fout.println(" "); + int n = this.powerSpectrumEstimate[0].length; + for(int i=0; i<n; i++){ + fout.printtab(Fmath.truncate(this.powerSpectrumEstimate[0][i], 4)); + fout.println(Fmath.truncate(this.powerSpectrumEstimate[1][i], 4)); + } + fout.close(); + } + + // Display a plot of the power spectrum from the given point number + // no graph title provided + public void plotPowerSpectrum(int lowPoint){ + String graphTitle = "Estimation of Power Spectrum Density"; + this.plotPowerSpectrum(lowPoint, this.powerSpectrumEstimate[0].length-1, graphTitle); + } + + // Display a plot of the power spectrum from the given point number + // graph title provided + public void plotPowerSpectrum(int lowPoint, String graphTitle){ + this.plotPowerSpectrum(lowPoint, this.powerSpectrumEstimate[0].length-1, graphTitle); + } + + // Display a plot of the power spectrum within a defined points window + // no graph title provided + public void plotPowerSpectrum(int lowPoint, int highPoint){ + String graphTitle = "Estimation of Power Spectrum Density"; + this.plotPowerSpectrum(lowPoint, highPoint, graphTitle); + } + + // Display a plot of the power spectrum within a defined points window + // Graph title provided + public void plotPowerSpectrum(int lowPoint, int highPoint, String graphTitle){ + if(!this.powSpecDone){ + System.out.println("plotPowerSpectrum - powerSpectrum has not been called - no plot displayed"); + } + else{ + int n = this.powerSpectrumEstimate[0].length-1; + if(lowPoint<0 || lowPoint>=n)lowPoint=0; + if(highPoint<0 || highPoint>n)highPoint=n; + this.plotPowerSpectrumLinear(lowPoint, highPoint, graphTitle); + } + } + + // Display a plot of the power spectrum from a given frequency + // no graph title provided + public void plotPowerSpectrum(double lowFreq){ + String graphTitle = "Estimation of Power Spectrum Density"; + this.plotPowerSpectrum(lowFreq, graphTitle); + } + + + // Display a plot of the power spectrum from a given frequency + // graph title provided + public void plotPowerSpectrum(double lowFreq, String graphTitle){ + if(!this.powSpecDone)this.powerSpectrum(); + + double highFreq = this.powerSpectrumEstimate[1][this.powerSpectrumEstimate[0].length-1]; + this.plotPowerSpectrum(lowFreq, highFreq, graphTitle); + } + + + // Display a plot of the power spectrum within a defined frequency window + // no graph title provided + public void plotPowerSpectrum(double lowFreq, double highFreq){ + if(!this.powSpecDone){ + System.out.println("plotPowerSpectrum - powerSpectrum has not been called - no plot displayed"); + } + else{ + String graphTitle = "Estimation of Power Spectrum Density"; + this.plotPowerSpectrum(lowFreq, highFreq, graphTitle); + } + } + + // Display a plot of the power spectrum within a defined frequency window + // graph title provided + public void plotPowerSpectrum(double lowFreq, double highFreq, String graphTitle){ + if(!this.powSpecDone){ + System.out.println("plotPowerSpectrum - powerSpectrum has not been called - no plot displayed"); + } + else{ + int low = 0; + int high = 0; + if(!this.deltaTset){ + System.out.println("plotPowerSpectrum - deltaT has not been set"); + System.out.println("full spectrum plotted"); + } + else{ + int ii = 0; + int n = this.powerSpectrumEstimate[0].length - 1; + boolean test = true; + if(lowFreq==-1.0D){ + low = 1; + } + else{ + while(test){ + if(this.powerSpectrumEstimate[0][ii]>lowFreq){ + low=ii-1; + if(low<0)low=0; + test = false; + } + else{ + ii++; + if(ii>=n){ + low = 0; + System.out.println("plotPowerSpectrum - lowFreq out of range - reset to zero"); + test = false; + } + } + } + } + test = true; + ii = 0; + while(test){ + if(this.powerSpectrumEstimate[0][ii]>highFreq){ + high=ii-1; + if(high<0){ + System.out.println("plotPowerSpectrum - highFreq out of range - reset to highest value"); + high = n; + } + test = false; + } + else{ + ii++; + if(ii>=n){ + high = n; + System.out.println("plotPowerSpectrum - highFreq out of range - reset to highest value"); + test = false; + } + } + } + this.plotPowerSpectrumLinear(low, high, graphTitle); + } + } + } + + + // Display a plot of the power spectrum + // no graph title provided + public void plotPowerSpectrum(){ + if(!this.powSpecDone)this.powerSpectrum(); + + String graphTitle = "Estimation of Power Spectrum Density"; + this.plotPowerSpectrumLinear(0, this.powerSpectrumEstimate[0].length-1, graphTitle); + } + + // Display a plot of the power spectrum + public void plotPowerSpectrum(String graphTitle){ + if(!this.powSpecDone)this.powerSpectrum(); + + this.plotPowerSpectrumLinear(0, this.powerSpectrumEstimate[0].length-1, graphTitle); + } + + // Prepare a plot of the power spectrum (linear) + private void plotPowerSpectrumLinear(int low, int high, String graphTitle){ + + int nData = this.powerSpectrumEstimate[0].length; + int nNew = high - low + 1; + double[][] spectrum = new double[2][nNew]; + for(int i=0; i<nNew; i++){ + spectrum[0][i] = this.powerSpectrumEstimate[0][i+low]; + spectrum[1][i] = this.powerSpectrumEstimate[1][i+low]; + } + String yLegend = "Mean Square Amplitude"; + + plotPowerDisplay(spectrum, low, high, graphTitle, yLegend); + } + + // Display a log plot of the power spectrum from the given point number + // no graph title provided + public void plotPowerLog(int lowPoint){ + String graphTitle = "Estimation of Power Spectrum Density"; + this.plotPowerLog(lowPoint, this.powerSpectrumEstimate[0].length-1, graphTitle); + } + + // Display a log plot of the power spectrum from the given point number + // graph title provided + public void plotPowerLog(int lowPoint, String graphTitle){ + this.plotPowerLog(lowPoint, this.powerSpectrumEstimate[0].length-1, graphTitle); + } + + // Display a log plot of the power spectrum within a defined points window + // no graph title provided + public void plotPowerLog(int lowPoint, int highPoint){ + String graphTitle = "Estimation of Power Spectrum Density"; + this.plotPowerLog(lowPoint, highPoint, graphTitle); + } + + // Display a plot of the power spectrum within a defined points window + // Graph title provided + public void plotPowerLog(int lowPoint, int highPoint, String graphTitle){ + if(!this.powSpecDone)this.powerSpectrum(); + + int n = this.powerSpectrumEstimate[0].length-1; + if(lowPoint<0 || lowPoint>=n)lowPoint=0; + if(highPoint<0 || highPoint>n)highPoint=n; + this.plotPowerSpectrumLog(lowPoint, highPoint, graphTitle); + } + + // Display a plot of the power spectrum from a given frequency + // no graph title provided + public void plotPowerLog(double lowFreq){ + String graphTitle = "Estimation of Power Spectrum Density"; + this.plotPowerLog(lowFreq, graphTitle); + } + + + // Display a log plot of the power spectrum from a given frequency + // graph title provided + public void plotPowerLog(double lowFreq, String graphTitle){ + if(!this.powSpecDone)this.powerSpectrum(); + + double highFreq = this.powerSpectrumEstimate[1][this.powerSpectrumEstimate[0].length-1]; + this.plotPowerLog(lowFreq, highFreq, graphTitle); + } + + // Display a plot of the power spectrum within a defined frequency window + // no graph title provided + public void plotPowerLog(double lowFreq, double highFreq){ + if(!this.powSpecDone)this.powerSpectrum(); + + String graphTitle = "Estimation of Power Spectrum Density"; + this.plotPowerLog(lowFreq, highFreq, graphTitle); + } + + // Display a log plot of the power spectrum within a defined frequency window + // graph title provided + public void plotPowerLog(double lowFreq, double highFreq, String graphTitle){ + if(!this.powSpecDone)this.powerSpectrum(); + + int low = 0; + int high = 0; + if(!this.deltaTset){ + System.out.println("plotPowerLog - deltaT has not been set"); + System.out.println("full spectrum plotted"); + } + else{ + int ii = 0; + int n = this.powerSpectrumEstimate[0].length - 1; + boolean test = true; + if(lowFreq==-1.0D){ + low = 1; + } + else{ + while(test){ + if(this.powerSpectrumEstimate[0][ii]>lowFreq){ + low=ii-1; + if(low<0)low=0; + test = false; + } + else{ + ii++; + if(ii>=n){ + low = 0; + System.out.println("plotPowerLog - lowFreq out of range - reset to zero"); + test = false; + } + } + } + } + test = true; + ii = 0; + while(test){ + if(this.powerSpectrumEstimate[0][ii]>highFreq){ + high=ii-1; + if(high<0){ + System.out.println("plotPowerLog - highFreq out of range - reset to highest value"); + high = n; + } + test = false; + } + else{ + ii++; + if(ii>=n){ + high = n; + System.out.println("plotPowerSpectrum - highFreq out of range - reset to highest value"); + test = false; + } + } + } + this.plotPowerSpectrumLog(low, high, graphTitle); + } + } + + // Display a log plot of the power spectrum + // no graph title provided + public void plotPowerLog(){ + if(!this.powSpecDone)this.powerSpectrum(); + + String graphTitle = "Estimation of Power Spectrum Density"; + this.plotPowerSpectrumLog(0, this.powerSpectrumEstimate[0].length-1, graphTitle); + } + + // Display a log plot of the power spectrum + public void plotPowerLog(String graphTitle){ + if(!this.powSpecDone)this.powerSpectrum(); + + this.plotPowerSpectrumLog(0, this.powerSpectrumEstimate[0].length-1, graphTitle); + } + + // Prepare a plot of the power spectrum (log) + private void plotPowerSpectrumLog(int low, int high, String graphTitle){ + + int nData = this.powerSpectrumEstimate[0].length; + int nNew = high - low + 1; + double[][] spectrum = new double[2][nNew]; + for(int i=0; i<nNew; i++){ + spectrum[0][i] = this.powerSpectrumEstimate[0][i+low]; + spectrum[1][i] = this.powerSpectrumEstimate[1][i+low]; + } + + // Find minimum of amplitudes that is not zero + // find first non-zero value + boolean test = true; + int ii = 0; + double minimum = 0.0D; + while(test){ + if(spectrum[1][ii]>0.0D){ + minimum = spectrum[1][ii]; + test = false; + } + else{ + ii++; + if(ii>=nNew){ + test = false; + System.out.println("plotPowerSpectrumLog: no non-zero amplitudes"); + System.exit(0); + } + } + } + + // Find minimum + for(int i=ii+1; i<nNew; i++)if(spectrum[1][i]<minimum)minimum = spectrum[1][i]; + + // Replace zeros with minimum + for(int i=0; i<nNew; i++)if(spectrum[1][i]<=0.0D)spectrum[1][i] = minimum; + + // Take log to base 10 + for(int i=0; i<nNew; i++)spectrum[1][i] = Fmath.log10(spectrum[1][i]); + + // call display method + String yLegend = "Log10(Mean Square Amplitude)"; + plotPowerDisplay(spectrum, low, high, graphTitle, yLegend); + } + + + // Display a plot of the power spectrum + private void plotPowerDisplay(double[][] spectrum, int low, int high, String graphTitle, String yLegend){ + + + PlotGraph pg = new PlotGraph(spectrum); + graphTitle = graphTitle + " [plot between points " + low + " and " + high + "]"; + pg.setGraphTitle(graphTitle); + String graphTitle2 = "Window: "+this.windowNames[this.windowOption]; + if(this.windowOption==6)graphTitle2 += " - alpha = "+this.kaiserAlpha; + if(this.windowOption==7)graphTitle2 += " - alpha = "+this.gaussianAlpha; + graphTitle2 += ", "+this.segmentNumber+" segment/s of length "+this.segmentLength; + if(this.segmentNumber>1){ + if(this.overlap){ + graphTitle2 += ", segments overlap by 50%"; + } + else{ + graphTitle2 += ", segments do not overlap"; + } + } + + pg.setGraphTitle2(graphTitle2); + pg.setXaxisLegend("Frequency"); + if(this.deltaTset){ + pg.setXaxisUnitsName("cycles per unit time"); + } + else{ + pg.setXaxisUnitsName("cycles per grid point"); + } + pg.setYaxisLegend(yLegend); + + switch(this.plotLineOption){ + case 0: pg.setLine(3); + break; + case 1: pg.setLine(1); + break; + case 2: pg.setLine(2); + break; + default: pg.setLine(3); + } + + switch(this.plotPointOption){ + case 0: pg.setPoint(0); + break; + case 1: pg.setPoint(4); + break; + default: pg.setPoint(0); + } + + pg.plot(); + + } + + // Set the line option in plotting the power spectrum or correlation + // = 0 join points with straight lines + // = 1 cubic spline interpolation + // = 3 no line - only points + public void setPlotLineOption(int lineOpt){ + this.plotLineOption = lineOpt; + } + + // Get the line option in ploting the power spectrum or correlation + // = 0 join points with straight lines + // = 1 cubic spline interpolation + // = 3 no line - only points + public int getPlotLineOption(){ + return this.plotLineOption; + } + + // Set the point option in plotting the power spectrum or correlation + // = 0 no point symbol + // = 1 filled circles + public void setPlotPointOption(int pointOpt){ + this.plotPointOption = pointOpt; + } + + // Get the point option in plotting the power spectrum or correlation + // = 0 no point symbol + // = 1 filled circles + public int getPlotPointOption(){ + return this.plotPointOption; + } + + + // Return correlation of data already entered with data passed as this method's argument + // data must be real + public double[][] correlate(double[] data){ + int nLen = data.length; + if(!this.fftDataSet)throw new IllegalArgumentException("No data has been previously entered"); + if(nLen!=this.originalDataLength)throw new IllegalArgumentException("The two data sets to be correlated are of different length"); + if(!FourierTransform.checkPowerOfTwo(nLen))throw new IllegalArgumentException("The length of the correlation data sets is not equal to an integer power of two"); + + this.complexCorr = Complex.oneDarray(nLen); + for(int i=0; i<nLen; i++){ + this.complexCorr[i].setReal(data[i]); + this.complexCorr[i].setImag(0.0D); + } + + this.fftCorr = new double[2*nLen]; + int j=-1; + for(int i=0; i<nLen; i++){ + this.fftCorr[++j] = data[i]; + this.fftCorr[++j] = 0.0D; + } + + return correlation(nLen); + } + + // Return correlation of data1 and data2 passed as this method's arguments + // data must be real + public double[][] correlate(double[] data1, double[] data2){ + int nLen = data1.length; + int nLen2 = data2.length; + if(nLen!=nLen2)throw new IllegalArgumentException("The two data sets to be correlated are of different length"); + if(!FourierTransform.checkPowerOfTwo(nLen))throw new IllegalArgumentException("The length of the correlation data sets is not equal to an integer power of two"); + + this.fftDataLength = nLen; + this.complexData = Complex.oneDarray(this.fftDataLength); + for(int i=0; i<this.fftDataLength; i++){ + this.complexData[i].setReal(data1[i]); + this.complexData[i].setImag(0.0D); + } + + this.fftData = new double[2*this.fftDataLength]; + int j = 0; + for(int i=0; i<this.fftDataLength; i++){ + this.fftData[j] = data1[i]; + j++; + this.fftData[j] = 0.0D; + j++; + } + this.fftDataSet = true; + + this.fftDataWindow = new double[2*this.fftDataLength]; + this.weights = new double[this.fftDataLength]; + this.sumOfSquaredWeights = windowData(this.fftData, this.fftDataWindow, this.weights); + + this.transformedDataFft = new double[2*this.fftDataLength]; + this.transformedDataComplex = Complex.oneDarray(this.fftDataLength); + + this.complexCorr = Complex.oneDarray(nLen); + for(int i=0; i<nLen; i++){ + this.complexCorr[i].setReal(data2[i]); + this.complexCorr[i].setImag(0.0D); + } + + this.fftCorr = new double[2*nLen]; + j=-1; + for(int i=0; i<nLen; i++){ + this.fftCorr[++j] = data2[i]; + this.fftCorr[++j] = 0.0D; + } + + return correlation(nLen); + } + + // Returns the correlation of the data in fftData and fftCorr + private double[][] correlation(int nLen){ + + this.fftDataWindow = new double[2*nLen]; + this.fftCorrWindow = new double[2*nLen]; + this.weights = new double[nLen]; + + this.sumOfSquaredWeights = windowData(this.fftData, this.fftDataWindow, this.weights); + windowData(this.fftCorr, this.fftCorrWindow, this.weights); + + // Perform fft on first set of stored data + int isign = 1; + double[] hold1 = new double[2*nLen]; + for(int i=0; i<nLen*2; i++)hold1[i] = this.fftDataWindow[i]; + basicFft(hold1, nLen, isign); + + // Perform fft on second set of stored data + isign = 1; + double[] hold2 = new double[2*nLen]; + for(int i=0; i<nLen*2; i++)hold2[i] = this.fftCorrWindow[i]; + basicFft(hold2, nLen, isign); + + // multiply hold1 by complex congugate of hold2 + double[] hold3 = new double[2*nLen]; + int j=0; + for(int i=0; i<nLen; i++){ + hold3[j] = (hold1[j]*hold2[j] + hold1[j+1]*hold2[j+1])/nLen; + hold3[j+1] = (-hold1[j]*hold2[j+1] + hold1[j+1]*hold2[j])/nLen; + j += 2; + } + + // Inverse transform -> correlation + isign = -1; + basicFft(hold3, nLen, isign); + + // fill correlation array + for(int i=0; i<2*nLen; i++)this.transformedDataFft[i]=hold3[i]; + this.correlationArray = new double[2][nLen]; + j=0; + int k=nLen; + for(int i=nLen/2+1; i<nLen; i++){ + this.correlationArray[1][j] = hold3[k]/nLen; + j++; + k+=2; + } + k=0; + for(int i=0; i<nLen/2; i++){ + this.correlationArray[1][j] = hold3[k]/nLen; + j++; + k+=2; + } + + // calculate time lags + this.correlationArray[0][0]= -(double)(nLen/2)*this.deltaT; + for(int i=1; i<nLen; i++){ + this.correlationArray[0][i] = this.correlationArray[0][i-1]+ this.deltaT; + } + + this.correlateDone = true; + return this.correlationArray; + } + + // Get the correlation + public double[][]getCorrelation(){ + if(!this.correlateDone){ + System.out.println("getCorrelation - correlation has not been called - no correlation returned"); + } + return this.correlationArray; + } + + // Print the correlation to a text file + // default file name + public void printCorrelation(){ + String filename = "Correlation.txt"; + printCorrelation(filename); + } + + // Print the correlation to a text file + public void printCorrelation(String filename){ + if(!this.correlateDone){ + System.out.println("printCorrelation - correlate has not been called - no file printed"); + } + else{ + FileOutput fout = new FileOutput(filename); + fout.println("Correlation Output File from FourierTransform"); + fout.dateAndTimeln(filename); + String title = "Window: "+this.windowNames[this.windowOption]; + if(this.windowOption==6)title += ", alpha = "+this.kaiserAlpha; + if(this.windowOption==7)title += ", alpha = "+this.gaussianAlpha; + fout.println(title); + fout.printtab("Data length = "); + fout.println(this.fftDataLength); + fout.println(); + + fout.printtab("Time lag"); + fout.println("Correlation"); + if(this.deltaTset){ + fout.printtab("/unit time"); + } + else{ + fout.printtab("/grid interval)"); + } + fout.println("Coefficient"); + + int n = this.correlationArray[0].length; + for(int i=0; i<n; i++){ + fout.printtab(Fmath.truncate(this.correlationArray[0][i], 4)); + fout.println(Fmath.truncate(this.correlationArray[1][i], 4)); + } + fout.close(); + } + } + + + // Display a plot of the correlation + // no graph title provided + public void plotCorrelation(){ + if(!this.correlateDone){ + System.out.println("plotCorrelation - correlation has not been called - no plot displayed"); + } + else{ + String graphTitle = "Correlation Plot"; + plotCorrelation(graphTitle); + } + } + + + // Display a plot of the correlation + public void plotCorrelation(String graphTitle){ + if(!this.correlateDone){ + System.out.println("plotCorrelation - correlate has not been called - no plot displayed"); + } + else{ + + PlotGraph pg = new PlotGraph(this.correlationArray); + pg.setGraphTitle(graphTitle); + String graphTitle2 = "Window: "+this.windowNames[this.windowOption]; + if(this.windowOption==6)graphTitle2 += " - alpha = "+this.kaiserAlpha; + if(this.windowOption==7)graphTitle2 += " - alpha = "+this.gaussianAlpha; + + pg.setGraphTitle2(graphTitle2); + pg.setXaxisLegend("Correlation Lag"); + if(this.deltaTset){ + pg.setXaxisUnitsName("unit time"); + } + else{ + pg.setXaxisUnitsName("grid interval"); + } + pg.setYaxisLegend("Correlation coefficient"); + + switch(this.plotLineOption){ + case 0: pg.setLine(3); + break; + case 1: pg.setLine(1); + break; + case 2: pg.setLine(2); + break; + default: pg.setLine(3); + } + + switch(this.plotPointOption){ + case 0: pg.setPoint(0); + break; + case 1: pg.setPoint(4); + break; + default: pg.setPoint(0); + } + + pg.plot(); + } + } + + // Performs a fft power spectrum density (psd) estimation + // on a moving window throughout the original data set + // returning the results as a frequency time matrix + // windowLength is the length of the window in time units + public double[][] shortTime(double windowTime){ + int windowLength = (int)Math.round(windowTime/this.deltaT); + if(!this.checkPowerOfTwo(windowLength)){ + int low = this.lastPowerOfTwo(windowLength); + int high = this.nextPowerOfTwo(windowLength); + + if((windowLength - low)<=(high-windowLength)){ + windowLength = low; + if(low==0)windowLength=high; + } + else{ + windowLength = high; + } + System.out.println("Method - shortTime"); + System.out.println("Window length, provided as time, "+windowTime+", did not convert to an integer power of two data points"); + System.out.println("A value of "+((windowLength-1)*this.deltaT)+" was substituted"); + } + + return shortTime(windowLength); + } + + // Performs a fft power spectrum density (psd) estimation + // on a moving window throughout the original data set + // returning the results as a frequency time matrix + // windowLength is the number of points in the window + public double[][] shortTime(int windowLength){ + + if(!FourierTransform.checkPowerOfTwo(windowLength))throw new IllegalArgumentException("Moving window data length ," + windowLength + ", is not an integer power of two"); + if(!this.fftDataSet)throw new IllegalArgumentException("No data has been entered for the Fast Fourier Transform"); + if(windowLength>this.originalDataLength)throw new IllegalArgumentException("The window length, " + windowLength + ", is greater than the data length, " + this.originalDataLength + "."); + + // if no window option has been set - default = Gaussian with alpha = 2.5 + if(this.windowOption==0)this.setGaussian(); + // set up time-frequency matrix + // first row = blank cell followed by time vector + // first column = blank cell followed by frequency vector + // each cell is then the mean square amplitude at that frequency and time + this.numShortTimes = this.originalDataLength - windowLength + 1; + this.numShortFreq = windowLength/2; + this.timeFrequency = new double[this.numShortFreq+1][this.numShortTimes+1]; + this.timeFrequency[0][0]=0.0D; + this.timeFrequency[0][1]=(double)(windowLength-1)*this.deltaT/2.0D; + for(int i=2;i<=this.numShortTimes;i++){ + this.timeFrequency[0][i] = this.timeFrequency[0][i-1] + this.deltaT; + } + for(int i=0;i<this.numShortFreq;i++){ + this.timeFrequency[i+1][0] = (double)i/((double)windowLength*this.deltaT); + } + + // set up window details + this.segmentLength = windowLength; + int windowStartIndex = 0; + double[] data = new double[2*windowLength]; // holds data and transformed data for working window + double[] winPSD = new double[this.numShortFreq]; // holds psd for working window + int isign = 1; + + // loop through time shifts + for(int i=1; i<=this.numShortTimes; i++){ + + // collect window data + for(int j=0; j<2*windowLength; j++)data[j] = this.fftData[windowStartIndex+j]; + + // window data + if(i==1){ + this.sumOfSquaredWeights = this.windowData(data, data, this.weights); + } + else{ + int k=0; + for(int j=0; j<this.segmentLength; j++){ + data[k] = data[k]*this.weights[j]; + data[++k] = data[k]*this.weights[j]; + ++k; + } + } + + // perform fft on windowed segment + basicFft(data, windowLength, isign); + + // obtain weighted mean square amplitudes + winPSD[0] = Fmath.square(data[0]) + Fmath.square(data[1]); + for(int j=1; j<this.numShortFreq; j++){ + winPSD[j] = Fmath.square(data[2*j]) + Fmath.square(data[2*j+1]) + Fmath.square(data[2*windowLength-2*j]) + Fmath.square(data[2*windowLength-2*j+1]); + } + + // Normalise and place in time-frequency matrix + for(int j=0; j<this.numShortFreq; j++){ + timeFrequency[j+1][i] = 2.0D*winPSD[j]/(windowLength*this.sumOfSquaredWeights); + } + + // increment segment start index + windowStartIndex += 2; + } + + this.shortTimeDone = true; + return this.timeFrequency; + } + + // Return time frequency matrix + public double[][] getTimeFrequencyMatrix(){ + if(!this.shortTimeDone)throw new IllegalArgumentException("No short time Fourier transform has been performed"); + return this.timeFrequency; + } + + // Return number of times in short time Fourier transform + public int getShortTimeNumberOfTimes(){ + if(!this.shortTimeDone)throw new IllegalArgumentException("No short time Fourier transform has been performed"); + return this.numShortTimes; + } + + // Return number of frequencies in short time Fourier transform + public int getShortTimeNumberOfFrequencies(){ + if(!this.shortTimeDone)throw new IllegalArgumentException("No short time Fourier transform has been performed"); + return this.numShortFreq; + } + + // Return number of points in short time Fourier transform window + public int getShortTimeWindowLength(){ + if(!this.shortTimeDone)throw new IllegalArgumentException("No short time Fourier transform has been performed"); + return this.segmentLength; + } + + // Print the short time Fourier transform to a text file + // default file name + public void printShortTime(){ + String filename = "ShortTime.txt"; + printShortTime(filename); + } + + // Print the short time Fourier transform to a text file + public void printShortTime(String filename){ + if(!this.shortTimeDone){ + System.out.println("printShortTime- shortTime has not been called - no file printed"); + } + else{ + FileOutput fout = new FileOutput(filename); + fout.println("Short Time Fourier Transform Output File from FourierTransform"); + fout.dateAndTimeln(filename); + String title = "Window: "+this.windowNames[this.windowOption]; + if(this.windowOption==6)title += ", alpha = "+this.kaiserAlpha; + if(this.windowOption==7)title += ", alpha = "+this.gaussianAlpha; + fout.println(title); + fout.printtab("Data length = "); + fout.println(this.originalDataLength); + fout.printtab("Delta T = "); + fout.println(this.deltaT); + fout.printtab("Window length (points) = "); + fout.println(this.segmentLength); + fout.printtab("Window length (time units) = "); + fout.println((this.segmentLength-1)*this.deltaT); + fout.printtab("Number of frequency points = "); + fout.println(this.numShortFreq); + fout.printtab("Number of time points = "); + fout.println(this.numShortTimes); + + // Average points if output would be greater than a text file line length + boolean checkAve = false; + int newTp = this.numShortTimes; + int maxN = 100; + int nAve = this.numShortTimes/maxN; + int nLast = this.numShortTimes % maxN; + if(this.numShortTimes>127){ + checkAve = true; + if(nLast>0){ + nAve += 1; + newTp = maxN; + nLast = this.numShortTimes - nAve*(newTp-1); + } + else{ + newTp = maxN; + nLast = nAve; + } + if(nLast!=nAve){ + fout.println("In the output below, each of the first " + (newTp-2) + " magnitude points, along the time axis, is the average of " + nAve + " calculated points"); + fout.println("The last point is the average of " + nLast + " calculated points"); + } + else{ + fout.println("In the output below, each magnitude point is the average of " + nAve + " calculated points"); + } + fout.println("The data, without averaging, may be accessed using the method getTimeFrequencyMatrix()"); + } + fout.println(); + + fout.println("first row = times"); + fout.println("first column = frequencies"); + fout.println("all other cells = mean square amplitudes at the corresponding time and frequency"); + if(checkAve){ + double sum = 0.0D; + int start = 1; + int workingAve = nAve; + for(int i=0; i<=this.numShortFreq;i++){ + fout.printtab(Fmath.truncate(this.timeFrequency[i][0], 4)); + start = 1; + for(int j=1; j<=newTp; j++){ + workingAve = nAve; + if(j==newTp)workingAve = nLast; + sum=0.0D; + for(int k=start; k<=(start+workingAve-1); k++){ + sum += this.timeFrequency[i][k]; + } + sum /= workingAve; + fout.printtab(Fmath.truncate(sum, 4)); + start += workingAve; + } + fout.println(); + } + } + else{ + for(int i=0; i<=this.numShortFreq;i++){ + for(int j=0; j<=newTp; j++){ + fout.printtab(Fmath.truncate(this.timeFrequency[i][j], 4)); + } + fout.println(); + } + } + fout.close(); + } + } + + // The paint method to draw the graph for plotShortTime. + public void paint(Graphics g){ + + // Call graphing method + graph(g); + } + + // Set up the window and show graph for short time Fourier transform + // user provided graph title + public void plotShortTime(String title){ + this.shortTitle = title; + plotShortTime(); + } + + // Set up the window and show graph for short time Fourier transform + // No user provided graph title + public void plotShortTime(){ + // Create the window object + JFrame window = new JFrame("Michael T Flanagan's plotting program - FourierTransform.plotShortTime"); + + // Set the initial size of the graph window + setSize(800, 600); + + // Set background colour + window.getContentPane().setBackground(Color.white); + + // Choose close box + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + // Add graph canvas + window.getContentPane().add("Center", this); + + // Set the window up + window.pack(); + window.setResizable(true); + window.toFront(); + + // Show the window + window.setVisible(true); + } + + + // graph method for plotShortTime short time Fourier Transform as a contour plot + public void graph(Graphics g){ + + // graph axes positions + int xLen = 512; + int yLen = 256; + int yTop = 100; + int xBot = 100; + int numBands = 18; + // colours for contour map + Color[] color = new Color[numBands+1]; + color[18] = Color.black; + color[17] = Color.darkGray; + color[16] = Color.gray; + color[15] = Color.lightGray; + color[14] = Color.red.darker(); + color[13] = Color.red; + color[12] = Color.magenta.darker(); + color[11] = Color.magenta; + color[10] = Color.pink; + color[9] = Color.pink.darker(); + color[8] = Color.orange.darker(); + color[7] = Color.orange; + color[6] = Color.yellow; + color[5] = Color.green; + color[4] = Color.green.darker(); + color[3] = Color.cyan; + color[2] = Color.cyan.darker(); + color[1] = Color.blue; + color[0] = Color.blue.darker(); + + // Check and set parameters in case need to average or expand to match fixed x-axis pixels + int pixelsPerXpoint = 0; + int xTp = 0; + int xAve = 0; + int xLast = 0; + boolean xCheck = true; + if(this.numShortTimes <= xLen){ + pixelsPerXpoint = xLen/this.numShortTimes; + xLen = pixelsPerXpoint*this.numShortTimes; + xTp = this.numShortTimes; + } + else{ + xCheck = false; + pixelsPerXpoint = 1; + xTp = this.numShortTimes; + xAve = this.numShortTimes/xLen; + xLast = this.numShortTimes % xLen; + if(xLast>0){ + xAve += 1; + xTp = this.numShortTimes/xAve+1; + xLast = this.numShortTimes - xAve*(xTp-1); + } + else{ + xTp = this.numShortTimes/xAve; + xLast = xAve; + } + xLen = xTp; + } + + // Check and set parameters in case need to average or expand to match fixed y-axis pixels + int pixelsPerYpoint = 0; + int yTp = 0; + int yAve = 0; + int yLast = 0; + boolean yCheck = true; + + if(this.numShortFreq <= yLen){ + pixelsPerYpoint = yLen/this.numShortFreq; + yLen = pixelsPerYpoint*this.numShortFreq; + yTp = this.numShortFreq; + } + else{ + yCheck = false; + pixelsPerYpoint = 1; + yTp = this.numShortFreq; + yAve = this.numShortFreq/yLen; + yLast = this.numShortFreq % yLen; + if(yLast>0){ + yAve += 1; + yTp = this.numShortFreq/yAve+1; + yLast = this.numShortFreq - yAve*(yTp-1); + } + else{ + yTp = this.numShortFreq/yAve; + yLast = yAve; + } + yLen = yTp; + } + + // Complete axes positions + int yBot = yTop + yLen; + int xTop = xBot + xLen; + + // declare contour map arrays + double[][] averages = new double[yTp][xTp]; + int[][] pixels = new int[yTp][xTp]; + double[] times = new double[xTp]; + int[] timesPixels = new int[xTp]; + double[] freqs = new double[yTp]; + int[] freqPixels = new int[yTp]; + + double[][] hold = new double[this.numShortFreq][xTp]; + + // If necessary average or expand to match fixed y-axis pixels + if(xCheck){ + for(int i=0; i<=this.numShortFreq; i++){ + for(int j=1; j<=this.numShortTimes; j++){ + if(i==0){ + times[j-1] = this.timeFrequency[0][j]; + } + else{ + hold[i-1][j-1] = this.timeFrequency[i][j]; + } + } + } + } + else{ + double sum = 0.0D; + int start = 1; + int workingAve = xAve; + for(int i=0; i<=this.numShortFreq;i++){ + start = 1; + for(int j=1; j<=xTp; j++){ + workingAve = xAve; + if(j==xTp)workingAve = xLast; + sum=0.0D; + for(int k=start; k<=(start+workingAve-1); k++){ + sum += this.timeFrequency[i][k]; + } + if(i==0){ + times[j-1] = sum/workingAve; + } + else{ + hold[i-1][j-1] = sum/workingAve; + } + start += workingAve; + } + } + } + + // If necessary average or expand to match fixed x-axis pixels + if(yCheck){ + for(int i=0; i<this.numShortFreq; i++){ + freqs[i] = this.timeFrequency[i+1][0]; + for(int j=0; j<xTp; j++){ + averages[i][j] = hold[i][j]; + } + } + } + else{ + double sum = 0.0D; + double sFreq = 0.0D; + int start = 0; + int workingAve = yAve; + for(int i=0; i<xTp;i++){ + start = 0; + for(int j=0; j<yTp; j++){ + workingAve = yAve; + if(j==yTp-1)workingAve = yLast; + sum = 0.0D; + sFreq = 0.0D; + for(int k=start; k<=(start+workingAve-1); k++){ + sum += hold[k][i]; + sFreq += this.timeFrequency[k+1][0]; + } + averages[j][i] = sum; + freqs[j] = sFreq/workingAve; + start += workingAve; + } + } + } + + // Calculate contour bands + double max = averages[0][0]; + double min = max; + for(int i=0; i<yTp; i++){ + for(int j=0; j<xTp; j++){ + if(averages[i][j]>max)max = averages[i][j]; + if(averages[i][j]<min)min = averages[i][j]; + } + } + + double bandZero = 0.0D; + if(min>0.1D*max)bandZero = 0.99D*min; + double bandWidth = (1.01D*max - 0.99D*min)/numBands; + double[] band = new double[numBands]; + band[0]=bandZero + bandWidth; + for(int i=1; i<numBands; i++){ + band[i] = band[i-1] + bandWidth; + } + boolean test = true; + for(int i=0; i<yTp; i++){ + for(int j=0; j<xTp; j++){ + test = true; + int k = 0; + while(test){ + if(averages[i][j]<=band[k]){ + pixels[i][j] = k; + test = false; + } + else{ + k++; + } + } + } + } + + // Plot contour coloured bands + int yPixels = 0; + int xPixels = 0; + int yInner = 0; + int xInner = 0; + int xx = xBot; + int yy = yTop; + for(int i=0; i<yTp; i++){ + for(int j=0; j<xTp; j++){ + yInner = 0; + for(int k=0; k<pixelsPerYpoint; k++){ + xInner = 0; + for(int l=0; l<pixelsPerXpoint; l++){ + g.setColor(color[pixels[i][j]]); + xx = xBot + (xPixels+xInner); + yy = yBot - (yPixels+yInner); + g.drawLine(xx, yy, xx, yy); + xInner++; + } + yInner++; + } + xPixels += xInner; + } + yPixels += yInner; + xPixels = 0; + } + + // draw axes + g.setColor(color[numBands]); + g.drawLine(xBot, yBot, xBot, yTop); + g.drawLine(xTop, yBot, xTop, yTop); + g.drawLine(xBot, yBot, xTop, yBot); + g.drawLine(xBot, yTop, xTop, yTop); + + // calculate axis legends and units + int yInc = yLen/4; + int yScale = this.numShortFreq/4; + double yUnits = yInc*(freqs[1]-freqs[0])/(pixelsPerYpoint*yScale); + String[] yArray = new String[5]; + int yArr = 0; + yArray[0] = "0 "; + for(int i=1; i<5; i++){ + yArr += yScale; + yArray[i] = yArr + " "; + } + xx = xBot; + yy = yBot; + int yWord = 6*(yArray[4].length()+1); + for(int i=0; i<5; i++){ + g.drawLine(xx-5, yy, xx, yy); + g.drawString(yArray[i], xx-yWord, yy+4); + yy -= yInc; + } + + int xInc = xLen/8; + int xScale = this.numShortTimes/8; + double xUnits = xInc*(times[1]-times[0])/(pixelsPerXpoint*xScale); + String[] xArray = new String[9]; + int xArr = 0; + xArray[0] = "0 "; + for(int i=1; i<9; i++){ + xArr += xScale; + xArray[i] = xArr + " "; + } + xx = xBot; + yy = yBot; + for(int i=0; i<9; i++){ + g.drawLine(xx, yy, xx, yy+5); + g.drawString(xArray[i], xx-4, yy+20); + xx += xInc; + } + + // write graph and axis legends and units + g.drawString("Short Time Fourier Transfer Time-Frequency Plot", xBot-80, yTop-80); + g.drawString(this.shortTitle, xBot-80, yTop-60); + + String yAxis = "Frequency / (" + Fmath.truncate(yUnits, 3) + " cycles per time unit)"; + g.drawString(yAxis, xBot-60, yTop-20); + String xAxis = "Time / (" + Fmath.truncate(xUnits, 3) + " time units)"; + g.drawString(xAxis, xBot, yBot+40); + String totalTime = "Total time = " + (Fmath.truncate((xLen*(times[1]-times[0]))/pixelsPerXpoint, 3)) + " time units"; + g.drawString(totalTime, xBot, yBot+80); + + String totalFreq = "Frequecy range = 0 to " + (Fmath.truncate((yLen*(freqs[1]-freqs[0]))/pixelsPerYpoint, 3)) + " cycles per time unit"; + g.drawString(totalFreq, xBot, yBot+100); + + g.drawString("Widow length = "+Fmath.truncate((this.segmentLength-1)*this.deltaT, 3)+" time units", xBot, yBot+120); + String filter = "Window filter = "+this.windowNames[this.windowOption]; + if(this.windowOption==6)filter += ", alpha = "+this.kaiserAlpha; + if(this.windowOption==7)filter += ", alpha = "+this.gaussianAlpha; + g.drawString(filter, xBot, yBot+140); + + // draw contour key + yy = yBot+100; + xx = xTop + 40; + double ss = Fmath.truncate(bandZero, 3); + for(int i=0; i<numBands; i++){ + double ff = Fmath.truncate(band[i], 3); + g.setColor(color[numBands]); + g.drawString(ss + " - " + ff, xx + 25, yy); + ss = ff; + g.setColor(color[i]); + for(int j=0; j<20; j++){ + yy = yy - 1; + g.drawLine(xx, yy, xx+20, yy); + } + } + g.setColor(Color.black); + g.drawString("Mean square", xx + 25, yy-25); + g.drawString("amplitudes ", xx + 25, yy-10); + + + + } + + // returns nearest power of two that is equal to or lower than argument length + public static int lastPowerOfTwo(int len){ + + boolean test0 = true; + while(test0){ + if(FourierTransform.checkPowerOfTwo(len)){ + test0 = false; + } + else{ + len--; + } + } + return len; + } + + // returns nearest power of two that is equal to or higher than argument length + public static int nextPowerOfTwo(int len){ + + boolean test0 = true; + while(test0){ + if(FourierTransform.checkPowerOfTwo(len)){ + test0 = false; + } + else{ + len++; + } + } + return len; + } + + // Checks whether the argument n is a power of 2 + public static boolean checkPowerOfTwo(int n){ + boolean test = true; + int m = n; + while(test && m>1){ + if((m % 2)!=0){ + test = false; + } + else{ + m /= 2; + } + } + return test; + } + + // Checks whether the argument n is an integer times a integer power of 2 + // returns integer multiplier if true + // returns zero if false + public static int checkIntegerTimesPowerOfTwo(int n){ + boolean testOuter1 = true; + boolean testInner1 = true; + boolean testInner2 = true; + boolean testReturn = true; + + int m = n; + int j = 1; + int mult = 0; + + while(testOuter1){ + testInner1 = FourierTransform.checkPowerOfTwo(m); + if(testInner1){ + testReturn = true; + testOuter1 = false; + } + else{ + testInner2 = true; + while(testInner2){ + m /= ++j; + if(m < 1){ + testInner2 = false; + testInner1 = false; + testOuter1 = false; + testReturn = false; + } + else{ + if((m % 2)==0)testInner2 = false; + } + } + } + } + if(testReturn)mult = j; + return mult; + } + + // Return the serial version unique identifier + public static long getSerialVersionUID(){ + return FourierTransform.serialVersionUID; + } + +} + + + + diff --git a/src/main/java/flanagan/math/GammaFunct.java b/src/main/java/flanagan/math/GammaFunct.java new file mode 100644 index 0000000000000000000000000000000000000000..7a4d99a4e7bd22497b4de0eb8d8cacd1b0c3bca6 --- /dev/null +++ b/src/main/java/flanagan/math/GammaFunct.java @@ -0,0 +1,19 @@ +package flanagan.math; + +import flanagan.analysis.Stat; +import flanagan.roots.RealRootFunction; + +// Class to evaluate the Gamma distribution function +public class GammaFunct implements RealRootFunction { + public double mu = 0.0D; + public double beta = 0.0D; + public double gamma = 0.0D; + public double cfd = 0.0D; + + public double function(double x){ + + double y = cfd - Stat.gammaCDF(mu, beta, gamma, x); + + return y; + } +} diff --git a/src/main/java/flanagan/math/LogNormalThreeParFunct.java b/src/main/java/flanagan/math/LogNormalThreeParFunct.java new file mode 100644 index 0000000000000000000000000000000000000000..7bbbe0c6670c86488328da17acc7110b47c14ae4 --- /dev/null +++ b/src/main/java/flanagan/math/LogNormalThreeParFunct.java @@ -0,0 +1,20 @@ +package flanagan.math; + +import flanagan.analysis.Stat; +import flanagan.roots.RealRootFunction; + +// Class to evaluate the three parameter log-normal distribution function +public class LogNormalThreeParFunct implements RealRootFunction { + + public double cfd = 0.0D; + public double alpha = 0.0D; + public double beta = 0.0D; + public double gamma = 0.0D; + + public double function(double x){ + + double y = cfd - Stat.logNormalThreeParCDF(alpha, beta, gamma, x); + + return y; + } +} diff --git a/src/main/java/flanagan/math/LogNormalTwoParFunct.java b/src/main/java/flanagan/math/LogNormalTwoParFunct.java new file mode 100644 index 0000000000000000000000000000000000000000..3ea41533353d38f0da420c1bfd842bd84531d9eb --- /dev/null +++ b/src/main/java/flanagan/math/LogNormalTwoParFunct.java @@ -0,0 +1,19 @@ +package flanagan.math; + +import flanagan.analysis.Stat; +import flanagan.roots.RealRootFunction; + +// Class to evaluate the two parameter log-normal distribution function +public class LogNormalTwoParFunct implements RealRootFunction { + + public double cfd = 0.0D; + public double mu = 0.0D; + public double sigma = 0.0D; + + public double function(double x){ + + double y = cfd - Stat.logNormalCDF(mu, sigma, x); + + return y; + } +} diff --git a/src/main/java/flanagan/math/Matrix.java b/src/main/java/flanagan/math/Matrix.java new file mode 100755 index 0000000000000000000000000000000000000000..474e715d8615ca16c0b9f703aaa363d56ffe4c55 --- /dev/null +++ b/src/main/java/flanagan/math/Matrix.java @@ -0,0 +1,2561 @@ +/* Class Matrix +* +* Defines a matrix and includes the methods needed +* for standard matrix manipulations, e.g. multiplation, +* and related procedures, e.g. solution of linear +* simultaneous equations +* +* See class ComplexMatrix and PhasorMatrix for complex matrix arithmetic +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: June 2002 +* UPDATES: 21 April 2004, 19 January 2005, 1 May 2005 +* 16 February 2006 Set methods corrected thanks to Myriam Servieres, Equipe IVC , Ecole Polytechnique de l'université de Nantes, Laboratoire IRCCyN/UMR CNRS +* 31 March 2006 Norm methods corrected thanks to Jinshan Wu, University of British Columbia +* 22 April 2006 getSubMatrix methods corrected thanks to Joachim Wesner +* 1 July 2007 row matrix, column matrix and division added +* 17 July 2007 solution of overdetermined linear equations and eigen values and vectros of a symmetric matrix added +* 18 August 2007 zero replacement in LU decompostion made a variable that the user may set +* 7 October 2007 get row and column numbers methods revised +* 27 February 2008 symmetric eigen method corrected - thanks to Mike Kroutikov +* 7 April 2008 and 5 July 2008 code tidying +* 6-15 September 2008 constructors extended, maximum element, minimum element and pivot methods added +* 7-14 October 2008 subtract means added, eigenvector methods updated +* 16 February 2009 - switched indices in FroebeniusNorm corrected - thanks to Istvan Szita, Rutgers University +* 16 June 2009 timesEquals corrected thanks to Bjorn Nordstom, Ericsonn +* 15 October 2009 - updated determinant method +* 4-5 November 2009 - Reduced Row Echelon Form added +* +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Matrix.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2009 Michael Thomas Flanagan +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.math; + +import flanagan.analysis.Regression; +import flanagan.analysis.RegressionFunction; +import flanagan.math.ArrayMaths; +import flanagan.analysis.Stat; + +import java.util.ArrayList; +import java.util.Vector; +import java.math.BigDecimal; +import java.math.BigInteger; + +public class Matrix{ + + private int numberOfRows = 0; // number of rows + private int numberOfColumns = 0; // number of columns + private double matrix[][] = null; // 2-D Matrix + private double hessenberg[][] = null; // 2-D Hessenberg equivalent + private boolean hessenbergDone = false; // = true when Hessenberg matrix calculated + private int permutationIndex[] = null; // row permutation index + private double rowSwapIndex = 1.0D; // row swap index + private double[] eigenValues = null; // eigen values of the matrix + private double[][] eigenVector = null; // eigen vectors of the matrix + private double[] sortedEigenValues = null; // eigen values of the matrix sorted into descending order + private double[][] sortedEigenVector = null; // eigen vectors of the matrix sorted to matching descending eigen value order + private int numberOfRotations = 0; // number of rotations in Jacobi transformation + private int[] eigenIndices = null; // indices of the eigen values before sorting into descending order + private int maximumJacobiIterations = 100; // maximum number of Jacobi iterations + private boolean eigenDone = false; // = true when eigen values and vectors calculated + private boolean matrixCheck = true; // check on matrix status + // true - no problems encountered in LU decomposition + // false - attempted a LU decomposition on a singular matrix + + private boolean supressErrorMessage = false; // true - LU decompostion failure message supressed + + private double tiny = 1.0e-100; // small number replacing zero in LU decomposition + + // CONSTRUCTORS + // Construct a numberOfRows x numberOfColumns matrix of variables all equal to zero + public Matrix(int numberOfRows, int numberOfColumns){ + this.numberOfRows = numberOfRows; + this.numberOfColumns = numberOfColumns; + this.matrix = new double[numberOfRows][numberOfColumns]; + this.permutationIndex = new int[numberOfRows]; + for(int i=0;i<numberOfRows;i++)this.permutationIndex[i]=i; + } + + // Construct a numberOfRows x numberOfColumns matrix of variables all equal to the number const + public Matrix(int numberOfRows, int numberOfColumns, double constant){ + this.numberOfRows = numberOfRows; + this.numberOfColumns = numberOfColumns; + this.matrix = new double[numberOfRows][numberOfColumns]; + for(int i=0;i<numberOfRows;i++){ + for(int j=0;j<numberOfColumns;j++)this.matrix[i][j]=constant; + } + this.permutationIndex = new int[numberOfRows]; + for(int i=0;i<numberOfRows;i++)this.permutationIndex[i]=i; + } + + // Construct matrix with a copy of an existing numberOfRows x numberOfColumns 2-D array of variables + public Matrix(double[][] twoD){ + this.numberOfRows = twoD.length; + this.numberOfColumns = twoD[0].length; + this.matrix = new double[this.numberOfRows][this.numberOfColumns]; + for(int i=0; i<numberOfRows; i++){ + if(twoD[i].length!=numberOfColumns)throw new IllegalArgumentException("All rows must have the same length"); + for(int j=0; j<numberOfColumns; j++){ + this.matrix[i][j]=twoD[i][j]; + } + } + this.permutationIndex = new int[numberOfRows]; + for(int i=0;i<numberOfRows;i++)this.permutationIndex[i]=i; + } + + // Construct matrix with a copy of an existing numberOfRows x numberOfColumns 2-D array of floats + public Matrix(float[][] twoD){ + this.numberOfRows = twoD.length; + this.numberOfColumns = twoD[0].length; + for(int i=1; i<numberOfRows; i++){ + if(twoD[i].length!=numberOfColumns)throw new IllegalArgumentException("All rows must have the same length"); + } + this.matrix = new double[this.numberOfRows][this.numberOfColumns]; + for(int i=0; i<numberOfRows; i++){ + for(int j=0; j<numberOfColumns; j++){ + this.matrix[i][j] = (double)twoD[i][j]; + } + } + this.permutationIndex = new int[numberOfRows]; + for(int i=0;i<numberOfRows;i++)this.permutationIndex[i]=i; + } + + // Construct matrix with a copy of an existing numberOfRows x numberOfColumns 2-D array of longs + public Matrix(long[][] twoD){ + this.numberOfRows = twoD.length; + this.numberOfColumns = twoD[0].length; + for(int i=1; i<numberOfRows; i++){ + if(twoD[i].length!=numberOfColumns)throw new IllegalArgumentException("All rows must have the same length"); + } + this.matrix = new double[this.numberOfRows][this.numberOfColumns]; + for(int i=0; i<numberOfRows; i++){ + for(int j=0; j<numberOfColumns; j++){ + this.matrix[i][j] = (double)twoD[i][j]; + } + } + this.permutationIndex = new int[numberOfRows]; + for(int i=0;i<numberOfRows;i++)this.permutationIndex[i]=i; + } + + + // Construct matrix with a copy of an existing numberOfRows x numberOfColumns 2-D array of ints + public Matrix(int[][] twoD){ + this.numberOfRows = twoD.length; + this.numberOfColumns = twoD[0].length; + for(int i=1; i<numberOfRows; i++){ + if(twoD[i].length!=numberOfColumns)throw new IllegalArgumentException("All rows must have the same length"); + } + this.matrix = new double[this.numberOfRows][this.numberOfColumns]; + for(int i=0; i<numberOfRows; i++){ + for(int j=0; j<numberOfColumns; j++){ + this.matrix[i][j] = (double)twoD[i][j]; + } + } + this.permutationIndex = new int[numberOfRows]; + for(int i=0;i<numberOfRows;i++)this.permutationIndex[i]=i; + } + + // Construct matrix with a copy of an existing numberOfRows 1-D array of ArrayMaths + public Matrix(ArrayMaths[] twoD){ + this.numberOfRows = twoD.length; + this.numberOfColumns = twoD[0].length(); + this.matrix = new double[this.numberOfRows][this.numberOfColumns]; + for(int i=0; i<numberOfRows; i++){ + double[] arrayh = (twoD[i].copy()).array(); + if(arrayh.length!=numberOfColumns)throw new IllegalArgumentException("All rows must have the same length"); + this.matrix[i] = arrayh; + } + this.permutationIndex = new int[numberOfRows]; + for(int i=0;i<numberOfRows;i++)this.permutationIndex[i]=i; + } + + // Construct matrix with a copy of an existing numberOfRows 1-D array of ArrayLists<Object> + public Matrix(ArrayList<Object>[] twoDal){ + this.numberOfRows = twoDal.length; + ArrayMaths[] twoD = new ArrayMaths[this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + twoD[i] = new ArrayMaths(twoDal[i]); + } + + this.numberOfColumns = twoD[0].length(); + this.matrix = new double[this.numberOfRows][this.numberOfColumns]; + for(int i=0; i<numberOfRows; i++){ + double[] arrayh = (twoD[i].copy()).array(); + if(arrayh.length!=numberOfColumns)throw new IllegalArgumentException("All rows must have the same length"); + this.matrix[i] = arrayh; + } + this.permutationIndex = new int[numberOfRows]; + for(int i=0;i<numberOfRows;i++)this.permutationIndex[i]=i; + } + + // Construct matrix with a copy of an existing numberOfRows 1-D array of Vector<Object> + public Matrix(Vector<Object>[] twoDv){ + this.numberOfRows = twoDv.length; + ArrayMaths[] twoD = new ArrayMaths[this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + twoD[i] = new ArrayMaths(twoDv[i]); + } + + this.numberOfColumns = twoD[0].length(); + this.matrix = new double[this.numberOfRows][this.numberOfColumns]; + for(int i=0; i<numberOfRows; i++){ + double[] arrayh = (twoD[i].copy()).array(); + if(arrayh.length!=numberOfColumns)throw new IllegalArgumentException("All rows must have the same length"); + this.matrix[i] = arrayh; + } + this.permutationIndex = new int[numberOfRows]; + for(int i=0;i<numberOfRows;i++)this.permutationIndex[i]=i; + } + + // Construct matrix with a copy of an existing numberOfRows x numberOfColumns 2-D array of BigDecimals + public Matrix(BigDecimal[][] twoD){ + this.numberOfRows = twoD.length; + this.numberOfColumns = twoD[0].length; + for(int i=1; i<numberOfRows; i++){ + if(twoD[i].length!=numberOfColumns)throw new IllegalArgumentException("All rows must have the same length"); + } + this.matrix = new double[this.numberOfRows][this.numberOfColumns]; + for(int i=0; i<numberOfRows; i++){ + for(int j=0; j<numberOfColumns; j++){ + this.matrix[i][j] = twoD[i][j].doubleValue(); + } + } + this.permutationIndex = new int[numberOfRows]; + for(int i=0;i<numberOfRows;i++)this.permutationIndex[i]=i; + } + + // Construct matrix with a copy of an existing numberOfRows x numberOfColumns 2-D array of BigIntegers + public Matrix(BigInteger[][] twoD){ + this.numberOfRows = twoD.length; + this.numberOfColumns = twoD[0].length; + for(int i=1; i<numberOfRows; i++){ + if(twoD[i].length!=numberOfColumns)throw new IllegalArgumentException("All rows must have the same length"); + } + this.matrix = new double[this.numberOfRows][this.numberOfColumns]; + for(int i=0; i<numberOfRows; i++){ + for(int j=0; j<numberOfColumns; j++){ + this.matrix[i][j] = twoD[i][j].doubleValue(); + } + } + this.permutationIndex = new int[numberOfRows]; + for(int i=0;i<numberOfRows;i++)this.permutationIndex[i]=i; + } + + + + // Construct matrix with a copy of the 2D matrix and permutation index of an existing Matrix bb. + public Matrix(Matrix bb){ + this.numberOfRows = bb.numberOfRows; + this.numberOfColumns = bb.numberOfColumns; + this.matrix = new double[this.numberOfRows][this.numberOfColumns]; + for(int i=0; i<numberOfRows; i++){ + for(int j=0; j<numberOfColumns; j++){ + this.matrix[i][j] = bb.matrix[i][j]; + } + } + this.permutationIndex = bb.permutationIndex.clone(); + this.rowSwapIndex = bb.rowSwapIndex; + } + + + // METHODS + // SET VALUES + // reset value of tiny used to replace zero in LU decompostions + // If not set: 1e-100 used + public void resetLUzero(double zeroValue){ + this.tiny = zeroValue; + } + + // Set the matrix with a copy of an existing numberOfRows x numberOfColumns 2-D matrix of variables + public void setTwoDarray(double[][] aarray){ + if(this.numberOfRows != aarray.length)throw new IllegalArgumentException("row length of this Matrix differs from that of the 2D array argument"); + if(this.numberOfColumns != aarray[0].length)throw new IllegalArgumentException("column length of this Matrix differs from that of the 2D array argument"); + for(int i=0; i<numberOfRows; i++){ + if(aarray[i].length!=numberOfColumns)throw new IllegalArgumentException("All rows must have the same length"); + for(int j=0; j<numberOfColumns; j++){ + this.matrix[i][j]=aarray[i][j]; + } + } + } + + // Set an individual array element + // i = row index + // j = column index + // aa = value of the element + public void setElement(int i, int j, double aa){ + this.matrix[i][j]=aa; + } + + // Set a sub-matrix starting with row index i, column index j + public void setSubMatrix(int i, int j, double[][] subMatrix){ + int k = subMatrix.length; + int l = subMatrix[0].length; + if(i>k)throw new IllegalArgumentException("row indices inverted"); + if(j>l)throw new IllegalArgumentException("column indices inverted"); + int n=k-i+1, m=l-j+1; + for(int p=0; p<n; p++){ + for(int q=0; q<m; q++){ + this.matrix[i+p][j+q] = subMatrix[p][q]; + } + } + } + + // Set a sub-matrix starting with row index i, column index j + // and ending with row index k, column index l + public void setSubMatrix(int i, int j, int k, int l, double[][] subMatrix){ + if(i>k)throw new IllegalArgumentException("row indices inverted"); + if(j>l)throw new IllegalArgumentException("column indices inverted"); + int n=k-i+1, m=l-j+1; + for(int p=0; p<n; p++){ + for(int q=0; q<m; q++){ + this.matrix[i+p][j+q] = subMatrix[p][q]; + } + } + } + + // Set a sub-matrix + // row = array of row indices + // col = array of column indices + public void setSubMatrix(int[] row, int[] col, double[][] subMatrix){ + int n=row.length; + int m=col.length; + for(int p=0; p<n; p++){ + for(int q=0; q<m; q++){ + this.matrix[row[p]][col[q]] = subMatrix[p][q]; + } + } + } + + // Get the value of matrixCheck + public boolean getMatrixCheck(){ + return this.matrixCheck; + } + + // SPECIAL MATRICES + // Construct an identity matrix + public static Matrix identityMatrix(int numberOfRows){ + Matrix special = new Matrix(numberOfRows, numberOfRows); + for(int i=0; i<numberOfRows; i++){ + special.matrix[i][i]=1.0; + } + return special; + } + + // Construct a square unit matrix + public static Matrix unitMatrix(int numberOfRows){ + Matrix special = new Matrix(numberOfRows, numberOfRows); + for(int i=0; i<numberOfRows; i++){ + for(int j=0; j<numberOfRows; j++){ + special.matrix[i][j]=1.0; + } + } + return special; + } + + // Construct a rectangular unit matrix + public static Matrix unitMatrix(int numberOfRows, int numberOfColumns){ + Matrix special = new Matrix(numberOfRows, numberOfColumns); + for(int i=0; i<numberOfRows; i++){ + for(int j=0; j<numberOfColumns; j++){ + special.matrix[i][j]=1.0; + } + } + return special; + } + + // Construct a square scalar matrix + public static Matrix scalarMatrix(int numberOfRows, double diagconst){ + Matrix special = new Matrix(numberOfRows, numberOfRows); + double[][] specialArray = special.getArrayReference(); + for(int i=0; i<numberOfRows; i++){ + for(int j=i; j<numberOfRows; j++){ + if(i==j){ + specialArray[i][j]= diagconst; + } + } + } + return special; + } + + // Construct a rectangular scalar matrix + public static Matrix scalarMatrix(int numberOfRows, int numberOfColumns, double diagconst){ + Matrix special = new Matrix(numberOfRows, numberOfColumns); + double[][] specialArray = special.getArrayReference(); + for(int i=0; i<numberOfRows; i++){ + for(int j=i; j<numberOfColumns; j++){ + if(i==j){ + specialArray[i][j]= diagconst; + } + } + } + return special; + } + + // Construct a square diagonal matrix + public static Matrix diagonalMatrix(int numberOfRows, double[] diag){ + if(diag.length!=numberOfRows)throw new IllegalArgumentException("matrix dimension differs from diagonal array length"); + Matrix special = new Matrix(numberOfRows, numberOfRows); + double[][] specialArray = special.getArrayReference(); + for(int i=0; i<numberOfRows; i++){ + specialArray[i][i]=diag[i]; + } + return special; + } + + // Construct a rectangular diagonal matrix + public static Matrix diagonalMatrix(int numberOfRows, int numberOfColumns, double[] diag){ + if(diag.length!=numberOfRows)throw new IllegalArgumentException("matrix dimension differs from diagonal array length"); + Matrix special = new Matrix(numberOfRows, numberOfColumns); + double[][] specialArray = special.getArrayReference(); + for(int i=0; i<numberOfRows; i++){ + for(int j=i; j<numberOfColumns; j++){ + if(i==j){ + specialArray[i][j]= diag[i]; + } + } + } + return special; + } + + // GET VALUES + // Return the number of rows + public int getNumberOfRows(){ + return this.numberOfRows; + } + + // Return the number of rows + public int getNrow(){ + return this.numberOfRows; + } + + // Return the number of columns + public int getNumberOfColumns(){ + return this.numberOfColumns; + } + + // Return the number of columns + public int getNcol(){ + return this.numberOfColumns; + } + + // Return a reference to the internal 2-D array + public double[][] getArrayReference(){ + return this.matrix; + } + + // Return a reference to the internal 2-D array + // included for backward compatibility with incorrect earlier documentation + public double[][] getArrayPointer(){ + return this.matrix; + } + + // Return a copy of the internal 2-D array + public double[][] getArrayCopy(){ + double[][] c = new double[this.numberOfRows][this.numberOfColumns]; + for(int i=0; i<numberOfRows; i++){ + for(int j=0; j<numberOfColumns; j++){ + c[i][j]=this.matrix[i][j]; + } + } + return c; + } + + // Return a copy of a row + public double[] getRowCopy(int i){ + if(i>=this.numberOfRows)throw new IllegalArgumentException("Row index, " + i + ", must be less than the number of rows, " + this.numberOfRows); + if(i<0)throw new IllegalArgumentException("Row index, " + i + ", must be zero or positive"); + return this.matrix[i].clone(); + } + + // Return a copy of a column + public double[] getColumnCopy(int ii){ + if(ii>=this.numberOfColumns)throw new IllegalArgumentException("Column index, " + ii + ", must be less than the number of columns, " + this.numberOfColumns); + if(ii<0)throw new IllegalArgumentException("column index, " + ii + ", must be zero or positive"); + double[] col = new double[this.numberOfRows]; + for(int i=0; i<numberOfRows; i++){ + col[i]=this.matrix[i][ii]; + } + return col; + } + + + // Return a single element of the internal 2-D array + public double getElement(int i, int j){ + return this.matrix[i][j]; + } + + // Return a single element of the internal 2-D array + // included for backward compatibility with incorrect earlier documentation + public double getElementCopy(int i, int j){ + return this.matrix[i][j]; + } + + // Return a single element of the internal 2-D array + // included for backward compatibility with incorrect earlier documentation + public double getElementPointer(int i, int j){ + return this.matrix[i][j]; + } + + // Return a sub-matrix starting with row index i, column index j + // and ending with row index k, column index l + public Matrix getSubMatrix(int i, int j, int k, int l){ + if(i>k)throw new IllegalArgumentException("row indices inverted"); + if(j>l)throw new IllegalArgumentException("column indices inverted"); + int n=k-i+1, m=l-j+1; + Matrix subMatrix = new Matrix(n, m); + double[][] sarray = subMatrix.getArrayReference(); + for(int p=0; p<n; p++){ + for(int q=0; q<m; q++){ + sarray[p][q]= this.matrix[i+p][j+q]; + } + } + return subMatrix; + } + + // Return a sub-matrix + // row = array of row indices + // col = array of column indices + public Matrix getSubMatrix(int[] row, int[] col){ + int n = row.length; + int m = col.length; + Matrix subMatrix = new Matrix(n, m); + double[][] sarray = subMatrix.getArrayReference(); + for(int i=0; i<n; i++){ + for(int j=0; j<m; j++){ + sarray[i][j]= this.matrix[row[i]][col[j]]; + } + } + return subMatrix; + } + + // Return a reference to the permutation index array + public int[] getIndexReference(){ + return this.permutationIndex; + } + + // Return a reference to the permutation index array + // included for backward compatibility with incorrect earlier documentation + public int[] getIndexPointer(){ + return this.permutationIndex; + } + + // Return a copy of the permutation index array + public int[] getIndexCopy(){ + int[] indcopy = new int[this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + indcopy[i]=this.permutationIndex[i]; + } + return indcopy; + } + + // Return the row swap index + public double getSwap(){ + return this.rowSwapIndex; + } + + // COPY + // Copy a Matrix [static method] + public static Matrix copy(Matrix a){ + if(a==null){ + return null; + } + else{ + int nr = a.getNumberOfRows(); + int nc = a.getNumberOfColumns(); + double[][] aarray = a.getArrayReference(); + Matrix b = new Matrix(nr,nc); + b.numberOfRows = nr; + b.numberOfColumns = nc; + double[][] barray = b.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + barray[i][j]=aarray[i][j]; + } + } + for(int i=0; i<nr; i++)b.permutationIndex[i] = a.permutationIndex[i]; + return b; + } + } + + // Copy a Matrix [instance method] + public Matrix copy(){ + if(this==null){ + return null; + } + else{ + int nr = this.numberOfRows; + int nc = this.numberOfColumns; + Matrix b = new Matrix(nr,nc); + double[][] barray = b.getArrayReference(); + b.numberOfRows = nr; + b.numberOfColumns = nc; + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + barray[i][j]=this.matrix[i][j]; + } + } + for(int i=0; i<nr; i++)b.permutationIndex[i] = this.permutationIndex[i]; + return b; + } + } + + // Clone a Matrix + public Object clone(){ + if(this==null){ + return null; + } + else{ + int nr = this.numberOfRows; + int nc = this.numberOfColumns; + Matrix b = new Matrix(nr,nc); + double[][] barray = b.getArrayReference(); + b.numberOfRows = nr; + b.numberOfColumns = nc; + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + barray[i][j]=this.matrix[i][j]; + } + } + for(int i=0; i<nr; i++)b.permutationIndex[i] = this.permutationIndex[i]; + return (Object) b; + } + } + + // COLUMN MATRICES + // Converts a 1-D array of doubles to a column matrix + public static Matrix columnMatrix(double[] darray){ + int nr = darray.length; + Matrix pp = new Matrix(nr, 1); + for(int i=0; i<nr; i++)pp.matrix[i][0] = darray[i]; + return pp; + } + + // ROW MATRICES + // Converts a 1-D array of doubles to a row matrix + public static Matrix rowMatrix(double[] darray){ + int nc = darray.length; + Matrix pp = new Matrix(1, nc); + for(int i=0; i<nc; i++)pp.matrix[0][i] = darray[i]; + return pp; + } + + // ADDITION + // Add this matrix to matrix B. This matrix remains unaltered [instance method] + public Matrix plus(Matrix bmat){ + if((this.numberOfRows!=bmat.numberOfRows)||(this.numberOfColumns!=bmat.numberOfColumns)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=bmat.numberOfRows; + int nc=bmat.numberOfColumns; + Matrix cmat = new Matrix(nr,nc); + double[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j] + bmat.matrix[i][j]; + } + } + return cmat; + } + + // Add this matrix to 2-D array B. This matrix remains unaltered [instance method] + public Matrix plus(double[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if((this.numberOfRows!=nr)||(this.numberOfColumns!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + + Matrix cmat = new Matrix(nr,nc); + double[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j] + bmat[i][j]; + } + } + return cmat; + } + + + // Add matrices A and B [static method] + public static Matrix plus(Matrix amat, Matrix bmat){ + if((amat.numberOfRows!=bmat.numberOfRows)||(amat.numberOfColumns!=bmat.numberOfColumns)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=amat.numberOfRows; + int nc=amat.numberOfColumns; + Matrix cmat = new Matrix(nr,nc); + double[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=amat.matrix[i][j] + bmat.matrix[i][j]; + } + } + return cmat; + } + + // Add matrix B to this matrix [equivalence of +=] + public void plusEquals(Matrix bmat){ + if((this.numberOfRows!=bmat.numberOfRows)||(this.numberOfColumns!=bmat.numberOfColumns)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=bmat.numberOfRows; + int nc=bmat.numberOfColumns; + + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + this.matrix[i][j] += bmat.matrix[i][j]; + } + } + } + + // SUBTRACTION + // Subtract matrix B from this matrix. This matrix remains unaltered [instance method] + public Matrix minus(Matrix bmat){ + if((this.numberOfRows!=bmat.numberOfRows)||(this.numberOfColumns!=bmat.numberOfColumns)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=this.numberOfRows; + int nc=this.numberOfColumns; + Matrix cmat = new Matrix(nr,nc); + double[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j] - bmat.matrix[i][j]; + } + } + return cmat; + } + + // Subtract a 2-D array from this matrix. This matrix remains unaltered [instance method] + public Matrix minus(double[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if((this.numberOfRows!=nr)||(this.numberOfColumns!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + + Matrix cmat = new Matrix(nr,nc); + double[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=this.matrix[i][j] - bmat[i][j]; + } + } + return cmat; + } + + + // Subtract matrix B from matrix A [static method] + public static Matrix minus(Matrix amat, Matrix bmat){ + if((amat.numberOfRows!=bmat.numberOfRows)||(amat.numberOfColumns!=bmat.numberOfColumns)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=amat.numberOfRows; + int nc=amat.numberOfColumns; + Matrix cmat = new Matrix(nr,nc); + double[][] carray = cmat.getArrayReference(); + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + carray[i][j]=amat.matrix[i][j] - bmat.matrix[i][j]; + } + } + return cmat; + } + + // Subtract matrix B from this matrix [equivlance of -=] + public void minusEquals(Matrix bmat){ + if((this.numberOfRows!=bmat.numberOfRows)||(this.numberOfColumns!=bmat.numberOfColumns)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + int nr=bmat.numberOfRows; + int nc=bmat.numberOfColumns; + + for(int i=0; i<nr; i++){ + for(int j=0; j<nc; j++){ + this.matrix[i][j] -= bmat.matrix[i][j]; + } + } + } + + // MULTIPLICATION + // Multiply this matrix by a matrix. [instance method] + // This matrix remains unaltered. + public Matrix times(Matrix bmat){ + if(this.numberOfColumns!=bmat.numberOfRows)throw new IllegalArgumentException("Nonconformable matrices"); + + Matrix cmat = new Matrix(this.numberOfRows, bmat.numberOfColumns); + double [][] carray = cmat.getArrayReference(); + double sum = 0.0D; + + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<bmat.numberOfColumns; j++){ + sum=0.0D; + for(int k=0; k<this.numberOfColumns; k++){ + sum += this.matrix[i][k]*bmat.matrix[k][j]; + } + carray[i][j]=sum; + } + } + return cmat; + } + + // Multiply this matrix by a 2-D array. [instance method] + // This matrix remains unaltered. + public Matrix times(double[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + + if(this.numberOfColumns!=nr)throw new IllegalArgumentException("Nonconformable matrices"); + + Matrix cmat = new Matrix(this.numberOfRows, nc); + double [][] carray = cmat.getArrayReference(); + double sum = 0.0D; + + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<nc; j++){ + sum=0.0D; + for(int k=0; k<this.numberOfColumns; k++){ + sum += this.matrix[i][k]*bmat[k][j]; + } + carray[i][j]=sum; + } + } + return cmat; + } + + // Multiply this matrix by a constant [instance method] + // This matrix remains unaltered + public Matrix times(double constant){ + Matrix cmat = new Matrix(this.numberOfRows, this.numberOfColumns); + double [][] carray = cmat.getArrayReference(); + + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + carray[i][j] = this.matrix[i][j]*constant; + } + } + return cmat; + } + + // Multiply two matrices {static method] + public static Matrix times(Matrix amat, Matrix bmat){ + if(amat.numberOfColumns!=bmat.numberOfRows)throw new IllegalArgumentException("Nonconformable matrices"); + + Matrix cmat = new Matrix(amat.numberOfRows, bmat.numberOfColumns); + double [][] carray = cmat.getArrayReference(); + double sum = 0.0D; + + for(int i=0; i<amat.numberOfRows; i++){ + for(int j=0; j<bmat.numberOfColumns; j++){ + sum=0.0D; + for(int k=0; k<amat.numberOfColumns; k++){ + sum += (amat.matrix[i][k]*bmat.matrix[k][j]); + } + carray[i][j]=sum; + } + } + return cmat; + } + + // Multiply a Matrix by a 2-D array of doubles [static method] + public static Matrix times(Matrix amat, double[][] bmat){ + if(amat.numberOfColumns!=bmat.length)throw new IllegalArgumentException("Nonconformable matrices"); + + Matrix cmat = new Matrix(amat.numberOfRows, bmat[0].length); + Matrix dmat = new Matrix(bmat); + double [][] carray = cmat.getArrayReference(); + double sum = 0.0D; + + for(int i=0; i<amat.numberOfRows; i++){ + for(int j=0; j<dmat.numberOfColumns; j++){ + sum=0.0D; + for(int k=0; k<amat.numberOfColumns; k++){ + sum += (amat.matrix[i][k]*dmat.matrix[k][j]); + } + carray[i][j]=sum; + } + } + return cmat; + } + + // Multiply a matrix by a constant [static method] + public static Matrix times(Matrix amat, double constant){ + Matrix cmat = new Matrix(amat.numberOfRows, amat.numberOfColumns); + double [][] carray = cmat.getArrayReference(); + + for(int i=0; i<amat.numberOfRows; i++){ + for(int j=0; j<amat.numberOfColumns; j++){ + carray[i][j] = amat.matrix[i][j]*constant; + } + } + return cmat; + } + + // Multiply this matrix by a matrix [equivalence of *=] + public void timesEquals(Matrix bmat){ + if(this.numberOfColumns!=bmat.numberOfRows)throw new IllegalArgumentException("Nonconformable matrices"); + + Matrix cmat = new Matrix(this.numberOfRows, bmat.numberOfColumns); + double [][] carray = cmat.getArrayReference(); + double sum = 0.0D; + + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<bmat.numberOfColumns; j++){ + sum=0.0D; + for(int k=0; k<this.numberOfColumns; k++){ + sum += this.matrix[i][k]*bmat.matrix[k][j]; + } + carray[i][j]=sum; + } + } + + this.numberOfRows = cmat.numberOfRows; + this.numberOfColumns = cmat.numberOfColumns; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + this.matrix[i][j] = cmat.matrix[i][j]; + } + } + } + + // Multiply this matrix by a constant [equivalence of *=] + public void timesEquals(double constant){ + + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + this.matrix[i][j] *= constant; + } + } + } + + // DIVISION + // Divide this Matrix by a Matrix - instance method + public Matrix over(Matrix bmat){ + if((this.numberOfRows!=bmat.numberOfRows)||(this.numberOfColumns!=bmat.numberOfColumns)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + return this.times(bmat.inverse()); + } + + // Divide a Matrix by a Matrix - static method. + public Matrix over(Matrix amat, Matrix bmat){ + if((amat.numberOfRows!=bmat.numberOfRows)||(amat.numberOfColumns!=bmat.numberOfColumns)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + return amat.times(bmat.inverse()); + } + + + // Divide this Matrix by a 2-D array of doubles. + public Matrix over(double[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if((this.numberOfRows!=nr)||(this.numberOfColumns!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + + Matrix cmat = new Matrix(bmat); + return this.times(cmat.inverse()); + } + + // Divide a Matrix by a 2-D array of doubles - static method. + public Matrix over(Matrix amat, double[][] bmat){ + int nr=bmat.length; + int nc=bmat[0].length; + if((amat.numberOfRows!=nr)||(amat.numberOfColumns!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + + Matrix cmat = new Matrix(bmat); + return amat.times(cmat.inverse()); + } + + // Divide a 2-D array of doubles by a Matrix - static method. + public Matrix over(double[][] amat, Matrix bmat){ + int nr=amat.length; + int nc=amat[0].length; + if((bmat.numberOfRows!=nr)||(bmat.numberOfColumns!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + + Matrix cmat = new Matrix(amat); + return cmat.times(bmat.inverse()); + } + + // Divide a 2-D array of doubles by a 2-D array of doubles - static method. + public Matrix over(double[][] amat, double[][] bmat){ + int nr=amat.length; + int nc=amat[0].length; + if((bmat.length!=nr)||(bmat[0].length!=nc)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + + Matrix cmat = new Matrix(amat); + Matrix dmat = new Matrix(bmat); + return cmat.times(dmat.inverse()); + } + + // Divide a this matrix by a matrix[equivalence of /=] + public void overEquals(Matrix bmat){ + if((this.numberOfRows!=bmat.numberOfRows)||(this.numberOfColumns!=bmat.numberOfColumns)){ + throw new IllegalArgumentException("Array dimensions do not agree"); + } + Matrix cmat = new Matrix(bmat); + this.timesEquals(cmat.inverse()); + } + + // Divide this Matrix by a 2D array of doubles [equivalence of /=] + public void overEquals(double[][] bmat){ + Matrix pmat = new Matrix(bmat); + this.overEquals(pmat); + } + + // INVERSE + // Inverse of a square matrix [instance method] + public Matrix inverse(){ + int n = this.numberOfRows; + if(n!=this.numberOfColumns)throw new IllegalArgumentException("Matrix is not square"); + Matrix invmat = new Matrix(n, n); + + if(n==1){ + double[][] hold = this.getArrayCopy(); + if(hold[0][0]==0.0)throw new IllegalArgumentException("Matrix is singular"); + hold[0][0] = 1.0/hold[0][0]; + invmat = new Matrix(hold); + } + else{ + if(n==2){ + double[][] hold = this.getArrayCopy(); + double det = hold[0][0]*hold[1][1] - hold[0][1]*hold[1][0]; + if(det==0.0)throw new IllegalArgumentException("Matrix is singular"); + double[][] hold2 = new double[2][2]; + hold2[0][0] = hold[1][1]/det; + hold2[1][1] = hold[0][0]/det; + hold2[1][0] = -hold[1][0]/det; + hold2[0][1] = -hold[0][1]/det; + invmat = new Matrix(hold2); + } + else{ + double[] col = new double[n]; + double[] xvec = new double[n]; + double[][] invarray = invmat.getArrayReference(); + Matrix ludmat; + + ludmat = this.luDecomp(); + for(int j=0; j<n; j++){ + for(int i=0; i<n; i++)col[i]=0.0D; + col[j]=1.0; + xvec=ludmat.luBackSub(col); + for(int i=0; i<n; i++)invarray[i][j]=xvec[i]; + } + } + } + return invmat; + } + + // Inverse of a square matrix [static method] + public static Matrix inverse(Matrix amat){ + int n = amat.numberOfRows; + if(n!=amat.numberOfColumns)throw new IllegalArgumentException("Matrix is not square"); + Matrix invmat = new Matrix(n, n); + + if(n==1){ + double[][] hold = amat.getArrayCopy(); + if(hold[0][0]==0.0)throw new IllegalArgumentException("Matrix is singular"); + hold[0][0] = 1.0/hold[0][0]; + invmat = new Matrix(hold); + } + else{ + if(n==2){ + double[][] hold = amat.getArrayCopy(); + double det = hold[0][0]*hold[1][1] - hold[0][1]*hold[1][0]; + if(det==0.0)throw new IllegalArgumentException("Matrix is singular"); + double[][] hold2 = new double[2][2]; + hold2[0][0] = hold[1][1]/det; + hold2[1][1] = hold[0][0]/det; + hold2[1][0] = -hold[1][0]/det; + hold2[0][1] = -hold[0][1]/det; + invmat = new Matrix(hold2); + } + else{ + double[] col = new double[n]; + double[] xvec = new double[n]; + double[][] invarray = invmat.getArrayReference(); + Matrix ludmat; + + ludmat = amat.luDecomp(); + for(int j=0; j<n; j++){ + for(int i=0; i<n; i++)col[i]=0.0D; + col[j]=1.0; + xvec=ludmat.luBackSub(col); + for(int i=0; i<n; i++)invarray[i][j]=xvec[i]; + } + } + } + return invmat; + } + + // TRANSPOSE + // Transpose of a matrix [instance method] + public Matrix transpose(){ + Matrix tmat = new Matrix(this.numberOfColumns, this.numberOfRows); + double[][] tarray = tmat.getArrayReference(); + for(int i=0; i<this.numberOfColumns; i++){ + for(int j=0; j<this.numberOfRows; j++){ + tarray[i][j]=this.matrix[j][i]; + } + } + return tmat; + } + + // Transpose of a matrix [static method] + public static Matrix transpose(Matrix amat){ + Matrix tmat = new Matrix(amat.numberOfColumns, amat.numberOfRows); + double[][] tarray = tmat.getArrayReference(); + for(int i=0; i<amat.numberOfColumns; i++){ + for(int j=0; j<amat.numberOfRows; j++){ + tarray[i][j]=amat.matrix[j][i]; + } + } + return tmat; + } + + // OPPOSITE + // Opposite of a matrix [instance method] + public Matrix opposite(){ + Matrix opp = Matrix.copy(this); + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + opp.matrix[i][j]=-this.matrix[i][j]; + } + } + return opp; + } + + // Opposite of a matrix [static method] + public static Matrix opposite(Matrix amat){ + Matrix opp = Matrix.copy(amat); + for(int i=0; i<amat.numberOfRows; i++){ + for(int j=0; j<amat.numberOfColumns; j++){ + opp.matrix[i][j]=-amat.matrix[i][j]; + } + } + return opp; + } + + // TRACE + // Trace of a matrix [instance method] + public double trace(){ + double trac = 0.0D; + for(int i=0; i<Math.min(this.numberOfColumns,this.numberOfColumns); i++){ + trac += this.matrix[i][i]; + } + return trac; + } + + // Trace of a matrix [static method] + public static double trace(Matrix amat){ + double trac = 0.0D; + for(int i=0; i<Math.min(amat.numberOfColumns,amat.numberOfColumns); i++){ + trac += amat.matrix[i][i]; + } + return trac; + } + + // DETERMINANT + // Returns the determinant of a square matrix [instance method] + public double determinant(){ + int n = this.numberOfRows; + if(n!=this.numberOfColumns)throw new IllegalArgumentException("Matrix is not square"); + double det = 0.0D; + if(n==2){ + det = this.matrix[0][0]*this.matrix[1][1] - this.matrix[0][1]*this.matrix[1][0]; + } + else{ + Matrix ludmat = this.luDecomp(); + det = ludmat.rowSwapIndex; + for(int j=0; j<n; j++){ + det *= ludmat.matrix[j][j]; + } + } + return det; + } + + // Returns the determinant of a square matrix [static method] - Matrix input + public static double determinant(Matrix amat){ + int n = amat.numberOfRows; + if(n!=amat.numberOfColumns)throw new IllegalArgumentException("Matrix is not square"); + double det = 0.0D; + + if(n==2){ + double[][] hold = amat.getArrayCopy(); + det = hold[0][0]*hold[1][1] - hold[0][1]*hold[1][0]; + } + else{ + Matrix ludmat = amat.luDecomp(); + det = ludmat.rowSwapIndex; + for(int j=0; j<n; j++){ + det *= (ludmat.matrix[j][j]); + } + } + return det; + } + + // Returns the determinant of a square matrix [static method] - [][] array input + public static double determinant(double[][]mat){ + int n = mat.length; + for(int i=0; i<n; i++)if(n!=mat[i].length)throw new IllegalArgumentException("Matrix is not square"); + double det = 0.0D; + + if(n==2){ + det = mat[0][0]*mat[1][1] - mat[0][1]*mat[1][0]; + } + else{ + Matrix amat = new Matrix(mat); + Matrix ludmat = amat.luDecomp(); + det = ludmat.rowSwapIndex; + for(int j=0; j<n; j++){ + det *= (ludmat.matrix[j][j]); + } + } + return det; + } + + // Returns the log(determinant) of a square matrix [instance method]. + // Useful if determinant() underflows or overflows. + public double logDeterminant(){ + int n = this.numberOfRows; + if(n!=this.numberOfColumns)throw new IllegalArgumentException("Matrix is not square"); + double det = 0.0D; + Matrix ludmat = this.luDecomp(); + + det = ludmat.rowSwapIndex; + det=Math.log(det); + for(int j=0; j<n; j++){ + det += Math.log(ludmat.matrix[j][j]); + } + return det; + } + + // Returns the log(determinant) of a square matrix [static method] - matrix input. + // Useful if determinant() underflows or overflows. + public static double logDeterminant(Matrix amat){ + int n = amat.numberOfRows; + if(n!=amat.numberOfColumns)throw new IllegalArgumentException("Matrix is not square"); + double det = 0.0D; + Matrix ludmat = amat.luDecomp(); + + det = ludmat.rowSwapIndex; + det=Math.log(det); + for(int j=0; j<n; j++){ + det += Math.log(ludmat.matrix[j][j]); + } + return det; + } + + // Returns the log(determinant) of a square matrix [static method] double[][] input. + // Useful if determinant() underflows or overflows. + public static double logDeterminant(double[][] mat){ + int n = mat.length; + for(int i=0; i<n; i++)if(n!=mat[i].length)throw new IllegalArgumentException("Matrix is not square"); + Matrix amat = new Matrix(mat); + return amat.determinant(); + } + + // REDUCED ROW ECHELON FORM + public Matrix reducedRowEchelonForm(){ + + double[][] mat = new double[this.numberOfRows][this.numberOfColumns]; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + mat[i][j] = this.matrix[i][j]; + } + } + + int leadingCoeff = 0; + int rowPointer = 0; + + boolean testOuter = true; + while(testOuter){ + int counter = rowPointer; + boolean testInner = true; + while(testInner && mat[counter][leadingCoeff] == 0) { + counter++; + if(counter == this.numberOfRows){ + counter = rowPointer; + leadingCoeff++; + if(leadingCoeff == this.numberOfColumns)testInner=false; + } + } + if(testInner){ + double[] temp = mat[rowPointer]; + mat[rowPointer] = mat[counter]; + mat[counter] = temp; + + double pivot = mat[rowPointer][leadingCoeff]; + for(int j=0; j<this.numberOfColumns; j++)mat[rowPointer][j] /= pivot; + + for(int i=0; i<this.numberOfRows; i++){ + if (i!=rowPointer) { + pivot = mat[i][leadingCoeff]; + for (int j=0; j<this.numberOfColumns; j++)mat[i][j] -= pivot * mat[rowPointer][j]; + } + } + leadingCoeff++; + if(leadingCoeff>=this.numberOfColumns)testOuter = false; + } + rowPointer++; + if(rowPointer>=this.numberOfRows || !testInner)testOuter = false; + } + + for(int i=0; i<this.numberOfRows; i++){ + for (int j=0; j<this.numberOfColumns; j++){ + if(mat[i][j]==-0.0)mat[i][j] = 0.0; + } + } + + return new Matrix(mat); + } + + // FROBENIUS NORM of a matrix + // Sometimes referred to as the EUCLIDEAN NORM + public double frobeniusNorm(){ + double norm=0.0D; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + norm=hypot(norm, Math.abs(matrix[i][j])); + } + } + return norm; + } + + + // ONE NORM of a matrix + public double oneNorm(){ + double norm = 0.0D; + double sum = 0.0D; + for(int i=0; i<this.numberOfRows; i++){ + sum=0.0D; + for(int j=0; j<this.numberOfColumns; j++){ + sum+=Math.abs(this.matrix[i][j]); + } + norm=Math.max(norm,sum); + } + return norm; + } + + // INFINITY NORM of a matrix + public double infinityNorm(){ + double norm = 0.0D; + double sum = 0.0D; + for(int i=0; i<this.numberOfRows; i++){ + sum=0.0D; + for(int j=0; j<this.numberOfColumns; j++){ + sum+=Math.abs(this.matrix[i][j]); + } + norm=Math.max(norm,sum); + } + return norm; + } + + // SUM OF THE ELEMENTS + // Returns sum of all elements + public double sum(){ + double sum = 0.0; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + sum += this.matrix[i][j]; + } + } + return sum; + } + + // Returns sums of the rows + public double[] rowSums(){ + double[] sums = new double[this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + sums[i] = 0.0; + for(int j=0; j<this.numberOfColumns; j++){ + sums[i] += this.matrix[i][j]; + } + } + return sums; + } + + // Returns sums of the columns + public double[] columnSums(){ + double[] sums = new double[this.numberOfColumns]; + for(int i=0; i<this.numberOfColumns; i++){ + sums[i] = 0.0; + for(int j=0; j<this.numberOfRows; j++){ + sums[i] += this.matrix[j][i]; + } + } + return sums; + } + + + + // MEAN OF THE ELEMENTS + // Returns mean of all elements + public double mean(){ + double mean = 0.0; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + mean += this.matrix[i][j]; + } + } + mean /= this.numberOfRows*this.numberOfColumns; + return mean; + } + + // Returns means of the rows + public double[] rowMeans(){ + double[] means = new double[this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + means[i] = 0.0; + for(int j=0; j<this.numberOfColumns; j++){ + means[i] += this.matrix[i][j]; + } + means[i] /= this.numberOfColumns; + } + return means; + } + + // Returns means of the columns + public double[] columnMeans(){ + double[] means = new double[this.numberOfColumns]; + for(int i=0; i<this.numberOfColumns; i++){ + means[i] = 0.0; + for(int j=0; j<this.numberOfRows; j++){ + means[i] += this.matrix[j][i]; + } + means[i] /= this.numberOfRows; + } + return means; + } + + // SUBTRACT THE MEAN OF THE ELEMENTS + // Returns a matrix whose elements are the original elements minus the mean of all elements + public Matrix subtractMean(){ + Matrix mat = new Matrix(this.numberOfRows, this.numberOfColumns); + + double mean = 0.0; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + mean += this.matrix[i][j]; + } + } + mean /= this.numberOfRows*this.numberOfColumns; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + mat.matrix[i][j] = this.matrix[i][j] - mean; + } + } + return mat; + } + + // Returns a matrix whose rows are the elements are the original row minus the mean of the elements of that row + public Matrix subtractRowMeans(){ + Matrix mat = new Matrix(this.numberOfRows, this.numberOfColumns); + + for(int i=0; i<this.numberOfRows; i++){ + double mean = 0.0; + for(int j=0; j<this.numberOfColumns; j++){ + mean += this.matrix[i][j]; + } + mean /= this.numberOfColumns; + for(int j=0; j<this.numberOfColumns; j++){ + mat.matrix[i][j] = this.matrix[i][j] - mean; + } + } + return mat; + } + + // Returns matrix whose columns are the elements are the original column minus the mean of the elements of that olumnc + public Matrix subtractColumnMeans(){ + Matrix mat = new Matrix(this.numberOfRows, this.numberOfColumns); + + for(int i=0; i<this.numberOfColumns; i++){ + double mean = 0.0; + for(int j=0; j<this.numberOfRows; j++){ + mean += this.matrix[j][i]; + } + mean /= this.numberOfRows; + for(int j=0; j<this.numberOfRows; j++){ + mat.matrix[j][i] = this.matrix[j][i] = mean; + } + } + return mat; + } + + + + // MEDIAN OF THE ELEMENTS + // Returns median of all elements + public double median(){ + Stat st = new Stat(this.matrix[0]); + + for(int i=1; i<this.numberOfRows; i++){ + st.concatenate(this.matrix[i]); + } + + return st.median(); + } + + // Returns medians of the rows + public double[] rowMedians(){ + double[] medians = new double[this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + Stat st = new Stat(this.matrix[i]); + medians[i] = st.median(); + } + + return medians; + } + + // Returns medians of the columns + public double[] columnMedians(){ + double[] medians = new double[this.numberOfRows]; + for(int i=0; i<this.numberOfColumns; i++){ + double[] hold = new double[this.numberOfRows]; + for(int j=0; j<this.numberOfRows; j++){ + hold[i] = this.matrix[j][i]; + } + Stat st = new Stat(hold); + medians[i] = st.median(); + } + + return medians; + } + + // SET THE DENOMINATOR OF THE VARIANCES AND STANDARD DEVIATIONS TO NUMBER OF ELEMENTS, n + // Default value = n-1 + public void setDenominatorToN(){ + Stat.setStaticDenominatorToN(); + } + + + // VARIANCE OF THE ELEMENTS + // Returns variance of all elements + public double variance(){ + Stat st = new Stat(this.matrix[0]); + + for(int i=1; i<this.numberOfRows; i++){ + st.concatenate(this.matrix[i]); + } + + return st.variance(); + } + + // Returns variances of the rows + public double[] rowVariances(){ + double[] variances = new double[this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + Stat st = new Stat(this.matrix[i]); + variances[i] = st.variance(); + } + + return variances; + } + + // Returns variances of the columns + public double[] columnVariances(){ + double[] variances = new double[this.numberOfColumns]; + for(int i=0; i<this.numberOfColumns; i++){ + double[] hold = new double[this.numberOfRows]; + for(int j=0; j<this.numberOfRows; j++){ + hold[i] = this.matrix[j][i]; + } + Stat st = new Stat(hold); + variances[i] = st.variance(); + } + + return variances; + } + + + + // STANDARD DEVIATION OF THE ELEMENTS + // Returns standard deviation of all elements + public double standardDeviation(){ + Stat st = new Stat(this.matrix[0]); + + for(int i=1; i<this.numberOfRows; i++){ + st.concatenate(this.matrix[i]); + } + + return st.standardDeviation(); + } + + // Returns standard deviations of the rows + public double[] rowStandardDeviations(){ + double[] standardDeviations = new double[this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + Stat st = new Stat(this.matrix[i]); + standardDeviations[i] = st.standardDeviation(); + } + + return standardDeviations; + } + + // Returns standard deviations of the columns + public double[] columnStandardDeviations(){ + double[] standardDeviations = new double[this.numberOfColumns]; + for(int i=0; i<this.numberOfColumns; i++){ + double[] hold = new double[this.numberOfRows]; + for(int j=0; j<this.numberOfRows; j++){ + hold[i] = this.matrix[j][i]; + } + Stat st = new Stat(hold); + standardDeviations[i] = st.standardDeviation(); + } + + return standardDeviations; + } + + + // STANDARD ERROR OF THE ELEMENTS + // Returns standard error of all elements + public double stanadardError(){ + Stat st = new Stat(this.matrix[0]); + + for(int i=1; i<this.numberOfRows; i++){ + st.concatenate(this.matrix[i]); + } + + return st.standardError(); + } + + // Returns standard errors of the rows + public double[] rowStandardErrors(){ + double[] standardErrors = new double[this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + Stat st = new Stat(this.matrix[i]); + standardErrors[i] = st.standardError(); + } + + return standardErrors; + } + + // Returns standard errors of the columns + public double[] columnStandardErrors(){ + double[] standardErrors = new double[this.numberOfRows]; + for(int i=0; i<this.numberOfColumns; i++){ + double[] hold = new double[this.numberOfRows]; + for(int j=0; j<this.numberOfRows; j++){ + hold[i] = this.matrix[j][i]; + } + Stat st = new Stat(hold); + standardErrors[i] = st.standardError(); + } + + return standardErrors; + } + + + + // MAXIMUM ELEMENT + // Returns the value, row index and column index of the maximum element + public double[] maximumElement(){ + double[] ret = new double[3]; + double[] holdD = new double[this.numberOfRows]; + ArrayMaths am = null; + int[] holdI = new int [this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + am = new ArrayMaths(this.matrix[i]); + holdD[i] = am.maximum(); + holdI[i] = am.maximumIndex(); + } + am = new ArrayMaths(holdD); + ret[0] = am.maximum(); + int maxI = am.maximumIndex(); + ret[1] = (double)maxI; + ret[2] = (double)holdI[maxI]; + + return ret; + } + + // Returns maxima of the rows + public double[] rowMaxima(){ + double[] maxima = new double[this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + Stat st = new Stat(this.matrix[i]); + maxima[i] = st.maximum(); + } + + return maxima; + } + + // Returns maxima of the columns + public double[] columnMaxima(){ + double[] maxima = new double[this.numberOfRows]; + for(int i=0; i<this.numberOfColumns; i++){ + double[] hold = new double[this.numberOfRows]; + for(int j=0; j<this.numberOfRows; j++){ + hold[i] = this.matrix[j][i]; + } + Stat st = new Stat(hold); + maxima[i] = st.maximum(); + } + + return maxima; + } + + // MINIMUM ELEMENT + // Returns the value, row index and column index of the minimum element + public double[] minimumElement(){ + double[] ret = new double[3]; + double[] holdD = new double[this.numberOfRows]; + ArrayMaths am = null; + int[] holdI = new int [this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + am = new ArrayMaths(this.matrix[i]); + holdD[i] = am.minimum(); + holdI[i] = am.minimumIndex(); + } + am = new ArrayMaths(holdD); + ret[0] = am.minimum(); + int minI = am.minimumIndex(); + ret[1] = (double)minI; + ret[2] = (double)holdI[minI]; + + return ret; + } + + // Returns minima of the rows + public double[] rowMinima(){ + double[] minima = new double[this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + Stat st = new Stat(this.matrix[i]); + minima[i] = st.minimum(); + } + + return minima; + } + + // Returns minima of the columns + public double[] columnMinima(){ + double[] minima = new double[this.numberOfRows]; + for(int i=0; i<this.numberOfColumns; i++){ + double[] hold = new double[this.numberOfRows]; + for(int j=0; j<this.numberOfRows; j++){ + hold[i] = this.matrix[j][i]; + } + Stat st = new Stat(hold); + minima[i] = st.minimum(); + } + + return minima; + } + + // RANGE + // Returns the range of all the elements + public double range(){ + return this.maximumElement()[0] - this.minimumElement()[0]; + } + + // Returns ranges of the rows + public double[] rowRanges(){ + double[] ranges = new double[this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + Stat st = new Stat(this.matrix[i]); + ranges[i] = st.maximum() - st.minimum(); + } + + return ranges; + } + + // Returns ranges of the columns + public double[] columnRanges(){ + double[] ranges = new double[this.numberOfRows]; + for(int i=0; i<this.numberOfColumns; i++){ + double[] hold = new double[this.numberOfRows]; + for(int j=0; j<this.numberOfRows; j++){ + hold[i] = this.matrix[j][i]; + } + Stat st = new Stat(hold); + ranges[i] = st.maximum() - st.minimum(); + } + + return ranges; + } + + // PIVOT + // Swaps rows and columns to place absolute maximum element in positiom matrix[0][0] + public int[] pivot(){ + double[] max = this.maximumElement(); + int maxI = (int)max[1]; + int maxJ = (int)max[2]; + double[] min = this.minimumElement(); + int minI = (int)min[1]; + int minJ = (int)min[2]; + if(Math.abs(min[0])>Math.abs(max[0])){ + maxI = minI; + maxJ = minJ; + } + int[] ret = {maxI, maxJ}; + + double[] hold1 = this.matrix[0]; + this.matrix[0] = this.matrix[maxI]; + this.matrix[maxI] = hold1; + double hold2 = 0.0; + for(int i=0; i<this.numberOfRows; i++){ + hold2 = this.matrix[i][0]; + this.matrix[i][0] = this.matrix[i][maxJ]; + this.matrix[i][maxJ] = hold2; + } + + return ret; + } + + // MATRIX TESTS + + // Check if a matrix is square + public boolean isSquare(){ + boolean test = false; + if(this.numberOfRows==this.numberOfColumns)test = true; + return test; + } + + // Check if a matrix is symmetric + public boolean isSymmetric(){ + boolean test = true; + if(this.numberOfRows==this.numberOfColumns){ + for(int i=0; i<this.numberOfRows; i++){ + for(int j=i+1; j<this.numberOfColumns; j++){ + if(this.matrix[i][j]!=this.matrix[j][i])test = false; + } + } + } + else{ + test = false; + } + return test; + } + + // Check if a matrix is zero + public boolean isZero(){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(this.matrix[i][j]!=0.0D)test = false; + } + } + return test; + } + + // Check if a matrix is unit + public boolean isUnit(){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(this.matrix[i][j]!=1.0D)test = false; + } + } + return test; + } + + // Check if a matrix is diagonal + public boolean isDiagonal(){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(i!=j && this.matrix[i][j]!=0.0D)test = false; + } + } + return test; + } + + // Check if a matrix is upper triagonal + public boolean isUpperTriagonal(){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(j<i && this.matrix[i][j]!=0.0D)test = false; + } + } + return test; + } + + // Check if a matrix is lower triagonal + public boolean isLowerTriagonal(){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(i>j && this.matrix[i][j]!=0.0D)test = false; + } + } + return test; + } + + // Check if a matrix is tridiagonal + public boolean isTridiagonal(){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(i<(j+1) && this.matrix[i][j]!=0.0D)test = false; + if(j>(i+1) && this.matrix[i][j]!=0.0D)test = false; + } + } + return test; + } + + // Check if a matrix is upper Hessenberg + public boolean isUpperHessenberg(){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(j<(i+1) && this.matrix[i][j]!=0.0D)test = false; + } + } + return test; + } + + // Check if a matrix is lower Hessenberg + public boolean isLowerHessenberg(){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(i>(j+1) && this.matrix[i][j]!=0.0D)test = false; + } + } + return test; + } + + // Check if a matrix is a identity matrix + public boolean isIdentity(){ + boolean test = true; + if(this.numberOfRows==this.numberOfColumns){ + for(int i=0; i<this.numberOfRows; i++){ + if(this.matrix[i][i]!=1.0D)test = false; + for(int j=i+1; j<this.numberOfColumns; j++){ + if(this.matrix[i][j]!=0.0D)test = false; + if(this.matrix[j][i]!=0.0D)test = false; + } + } + } + else{ + test = false; + } + return test; + } + + // Check if a matrix is symmetric within a given tolerance + public boolean isNearlySymmetric(double tolerance){ + boolean test = true; + if(this.numberOfRows==this.numberOfColumns){ + for(int i=0; i<this.numberOfRows; i++){ + for(int j=i+1; j<this.numberOfColumns; j++){ + if(Math.abs(this.matrix[i][j]-this.matrix[j][i])>Math.abs(tolerance))test = false; + } + } + } + else{ + test = false; + } + return test; + } + + // Check if a matrix is zero within a given tolerance + public boolean isNearlyZero(double tolerance){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(Math.abs(this.matrix[i][j])>Math.abs(tolerance))test = false; + } + } + return test; + } + + // Check if a matrix is unit within a given tolerance + public boolean isNearlyUnit(double tolerance){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(Math.abs(this.matrix[i][j] - 1.0D)>Math.abs(tolerance))test = false; + } + } + return test; + } + + + // Check if a matrix is upper triagonal within a given tolerance + public boolean isNearlyUpperTriagonal(double tolerance){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(j<i && this.matrix[i][j]>Math.abs(tolerance))test = false; + } + } + return test; + } + + // Check if a matrix is lower triagonal within a given tolerance + public boolean isNearlyLowerTriagonal(double tolerance){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(i>j && this.matrix[i][j]>Math.abs(tolerance))test = false; + } + } + return test; + } + + + + // Check if a matrix is an identy matrix within a given tolerance + public boolean isNearlyIdenty(double tolerance){ + boolean test = true; + if(this.numberOfRows==this.numberOfColumns){ + for(int i=0; i<this.numberOfRows; i++){ + if(Math.abs(this.matrix[i][i]-1.0D)>Math.abs(tolerance))test = false; + for(int j=i+1; j<this.numberOfColumns; j++){ + if(this.matrix[i][j]>Math.abs(tolerance))test = false; + if(this.matrix[j][i]>Math.abs(tolerance))test = false; + } + } + } + else{ + test = false; + } + return test; + } + + // Check if a matrix is tridiagonal within a given tolerance + public boolean isTridiagonal(double tolerance){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(i<(j+1) && this.matrix[i][j]>Math.abs(tolerance))test = false; + if(j>(i+1) && this.matrix[i][j]>Math.abs(tolerance))test = false; + } + } + return test; + } + + // Check if a matrix is upper Hessenberg within a given tolerance + public boolean isNearlyUpperHessenberg(double tolerance){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(j<(i+1) && this.matrix[i][j]>Math.abs(tolerance))test = false; + } + } + return test; + } + + // Check if a matrix is lower Hessenberg within a given tolerance + public boolean isNearlyLowerHessenberg(double tolerance){ + boolean test = true; + for(int i=0; i<this.numberOfRows; i++){ + for(int j=0; j<this.numberOfColumns; j++){ + if(i>(j+1) && this.matrix[i][j]>Math.abs(tolerance))test = false; + } + } + return test; + } + + // LU DECOMPOSITION OF MATRIX A + // For details of LU decomposition + // See Numerical Recipes, The Art of Scientific Computing + // by W H Press, S A Teukolsky, W T Vetterling & B P Flannery + // Cambridge University Press, http://www.nr.com/ + // This method has followed their approach but modified to an object oriented language + // Matrix ludmat is the returned LU decompostion + // int[] index is the vector of row permutations + // rowSwapIndex returns +1.0 for even number of row interchanges + // returns -1.0 for odd number of row interchanges + public Matrix luDecomp(){ + if(this.numberOfRows!=this.numberOfColumns)throw new IllegalArgumentException("A matrix is not square"); + int n = this.numberOfRows; + int imax = 0; + double dum = 0.0D, temp = 0.0D, big = 0.0D; + double[] vv = new double[n]; + double sum = 0.0D; + double dumm = 0.0D; + + this.matrixCheck = true; + + Matrix ludmat = Matrix.copy(this); + double[][] ludarray = ludmat.getArrayReference(); + + ludmat.rowSwapIndex=1.0D; + for (int i=0;i<n;i++) { + big=0.0D; + for (int j=0;j<n;j++)if ((temp=Math.abs(ludarray[i][j])) > big) big=temp; + if (big == 0.0D){ + if(!this.supressErrorMessage){ + System.out.println("Attempted LU Decomposition of a singular matrix in Matrix.luDecomp()"); + System.out.println("NaN matrix returned and matrixCheck set to false"); + } + this.matrixCheck=false; + for(int k=0;k<n;k++)for(int j=0;j<n;j++)ludarray[k][j]=Double.NaN; + return ludmat; + } + vv[i]=1.0/big; + } + for (int j=0;j<n;j++) { + for (int i=0;i<j;i++) { + sum=ludarray[i][j]; + for (int k=0;k<i;k++) sum -= ludarray[i][k]*ludarray[k][j]; + ludarray[i][j]=sum; + } + big=0.0D; + for (int i=j;i<n;i++) { + sum=ludarray[i][j]; + for (int k=0;k<j;k++) + sum -= ludarray[i][k]*ludarray[k][j]; + ludarray[i][j]=sum; + if ((dum=vv[i]*Math.abs(sum)) >= big) { + big=dum; + imax=i; + } + } + if (j != imax) { + for (int k=0;k<n;k++) { + dumm=ludarray[imax][k]; + ludarray[imax][k]=ludarray[j][k]; + ludarray[j][k]=dumm; + } + ludmat.rowSwapIndex = -ludmat.rowSwapIndex; + vv[imax]=vv[j]; + } + ludmat.permutationIndex[j]=imax; + + if(ludarray[j][j]==0.0D){ + ludarray[j][j]=this.tiny; + } + if(j != n-1) { + dumm=1.0/ludarray[j][j]; + for (int i=j+1;i<n;i++){ + ludarray[i][j]*=dumm; + } + } + } + return ludmat; + } + + // Solves the set of n linear equations A.X=B using not A but its LU decomposition + // bvec is the vector B (input) + // xvec is the vector X (output) + // index is the permutation vector produced by luDecomp() + public double[] luBackSub(double[] bvec){ + int ii = 0,ip = 0; + int n=bvec.length; + if(n!=this.numberOfColumns)throw new IllegalArgumentException("vector length is not equal to matrix dimension"); + if(this.numberOfColumns!=this.numberOfRows)throw new IllegalArgumentException("matrix is not square"); + double sum= 0.0D; + double[] xvec=new double[n]; + for(int i=0; i<n; i++){ + xvec[i]=bvec[i]; + } + for (int i=0;i<n;i++) { + ip=this.permutationIndex[i]; + sum=xvec[ip]; + xvec[ip]=xvec[i]; + if (ii==0){ + for (int j=ii;j<=i-1;j++){ + sum -= this.matrix[i][j]*xvec[j]; + } + } + else{ + if(sum==0.0) ii=i; + } + xvec[i]=sum; + } + for(int i=n-1;i>=0;i--) { + sum=xvec[i]; + for (int j=i+1;j<n;j++){ + sum -= this.matrix[i][j]*xvec[j]; + } + xvec[i]= sum/matrix[i][i]; + } + return xvec; + } + + // Solves the set of n linear equations A.X=B + // bvec is the vector B (input) + // xvec is the vector X (output) + public double[] solveLinearSet(double[] bvec){ + double[] xvec = null; + if(this.numberOfRows==this.numberOfColumns){ + // square matrix - LU decomposition used + Matrix ludmat = this.luDecomp(); + xvec = ludmat.luBackSub(bvec); + } + else{ + if(this.numberOfRows>this.numberOfColumns){ + // overdetermined equations - least squares used - must be used with care + int n = bvec.length; + if(this.numberOfRows!=n)throw new IllegalArgumentException("Overdetermined equation solution - vector length is not equal to matrix column length"); + Matrix avecT = this.transpose(); + double[][] avec = avecT.getArrayCopy(); + Regression reg = new Regression(avec, bvec); + reg.linearGeneral(); + xvec = reg.getCoeff(); + } + else{ + throw new IllegalArgumentException("This class does not handle underdetermined equations"); + } + } + return xvec; + } + + //Supress printing of LU decompostion failure message + public void supressErrorMessage(){ + this.supressErrorMessage = true; + } + + + // HESSENBERG MARTIX + + // Calculates the Hessenberg equivalant of this matrix + public void hessenbergMatrix(){ + + this.hessenberg = this.getArrayCopy(); + double pivot = 0.0D; + int pivotIndex = 0; + double hold = 0.0D; + + for(int i = 1; i<this.numberOfRows-1; i++){ + // identify pivot + pivot = 0.0D; + pivotIndex = i; + for(int j=i; j<this.numberOfRows; j++){ + if(Math.abs(this.hessenberg[j][i-1])> Math.abs(pivot)){ + pivot = this.hessenberg[j][i-1]; + pivotIndex = j; + } + } + + // row and column interchange + if(pivotIndex != i){ + for(int j = i-1; j<this.numberOfRows; j++){ + hold = this.hessenberg[pivotIndex][j]; + this.hessenberg[pivotIndex][j] = this.hessenberg[i][j]; + this.hessenberg[i][j] = hold; + } + for(int j = 0; j<this.numberOfRows; j++){ + hold = this.hessenberg[j][pivotIndex]; + this.hessenberg[j][pivotIndex] = this.hessenberg[j][i]; + this.hessenberg[j][i] = hold; + } + + // elimination + if(pivot!=0.0){ + for(int j=i+1; j<this.numberOfRows; j++){ + hold = this.hessenberg[j][i-1]; + if(hold!=0.0){ + hold /= pivot; + this.hessenberg[j][i-1] = hold; + for(int k=i; k<this.numberOfRows; k++){ + this.hessenberg[j][k] -= hold*this.hessenberg[i][k]; + } + for(int k=0; k<this.numberOfRows; k++){ + this.hessenberg[k][i] += hold*this.hessenberg[k][j]; + } + } + } + } + } + } + for(int i = 2; i<this.numberOfRows; i++){ + for(int j = 0; j<i-1; j++){ + this.hessenberg[i][j] = 0.0; + } + } + this.hessenbergDone = true; + } + + // return the Hessenberg equivalent + public double[][] getHessenbergMatrix(){ + if(!hessenbergDone)this.hessenbergMatrix(); + return this.hessenberg; + } + + + // EIGEN VALUES AND EIGEN VECTORS + // For a discussion of eigen systems see + // Numerical Recipes, The Art of Scientific Computing + // by W H Press, S A Teukolsky, W T Vetterling & B P Flannery + // Cambridge University Press, http://www.nr.com/ + // These methods follow their approach but modified to an object oriented language + + // Return eigen values as calculated + public double[] getEigenValues(){ + if(!this.eigenDone)symmetricEigen(); + return this.eigenValues; + } + + // Return eigen values in descending order + public double[] getSortedEigenValues(){ + if(!this.eigenDone)symmetricEigen(); + return this.sortedEigenValues; + } + + // Return eigen vectors as calculated as columns + // Each vector as a column + public double[][] getEigenVectorsAsColumns(){ + if(!this.eigenDone)symmetricEigen(); + return this.eigenVector; + } + // Return eigen vectors as calculated as columns + // Each vector as a column + public double[][] getEigenVector(){ + if(!this.eigenDone)symmetricEigen(); + return this.eigenVector; + } + + // Return eigen vectors as calculated as rows + // Each vector as a row + public double[][] getEigenVectorsAsRows(){ + if(!this.eigenDone)symmetricEigen(); + double[][] ret = new double[this.numberOfRows][this.numberOfRows]; + for(int i=0; i<this.numberOfRows;i++){ + for(int j=0; j<this.numberOfRows;j++){ + ret[i][j] = this.eigenVector[j][i]; + } + } + return ret; + } + + // Return eigen vectors reordered to match a descending order of eigen values + // Each vector as a column + public double[][] getSortedEigenVectorsAsColumns(){ + if(!this.eigenDone)symmetricEigen(); + return this.sortedEigenVector; + } + + // Return eigen vectors reordered to match a descending order of eigen values + // Each vector as a column + public double[][] getSortedEigenVector(){ + if(!this.eigenDone)symmetricEigen(); + return this.sortedEigenVector; + } + + // Return eigen vectors reordered to match a descending order of eigen values + // Each vector as a row + public double[][] getSortedEigenVectorsAsRows(){ + if(!this.eigenDone)symmetricEigen(); + double[][] ret = new double[this.numberOfRows][this.numberOfRows]; + for(int i=0; i<this.numberOfRows;i++){ + for(int j=0; j<this.numberOfRows;j++){ + ret[i][j] = this.sortedEigenVector[j][i]; + } + } + return ret; + } + + // Return the number of rotations used in the Jacobi procedure + public int getNumberOfJacobiRotations(){ + return this.numberOfRotations; + } + + // Returns the eigen values and eigen vectors of a symmetric matrix + // Follows the approach of Numerical methods but adapted to object oriented programming (see above) + private void symmetricEigen(){ + + if(!this.isSymmetric())throw new IllegalArgumentException("matrix is not symmetric"); + double[][] amat = this.getArrayCopy(); + this.eigenVector = new double[this.numberOfRows][this.numberOfRows]; + this.eigenValues = new double[this.numberOfRows]; + double threshold = 0.0D; + double cot2rotationAngle = 0.0D; + double tanHalfRotationAngle = 0.0D; + double offDiagonalSum = 0.0D; + double scaledOffDiagonal = 0.0D; + double sElement = 0.0D; + double cElement = 0.0D; + double sOverC = 0.0D; + double vectorDifference = 0.0D; + double[] holdingVector1 = new double[this.numberOfRows]; + double[] holdingVector2 = new double[this.numberOfRows]; + + for(int p=0;p<this.numberOfRows;p++){ + for(int q=0;q<this.numberOfRows;q++) this.eigenVector[p][q] = 0.0; + this.eigenVector[p][p] = 1.0; + } + for(int p=0;p<this.numberOfRows;p++){ + holdingVector1[p] = amat[p][p]; + this.eigenValues[p] = amat[p][p]; + holdingVector2[p] = 0.0; + } + this.numberOfRotations = 0; + for(int i=1;i<=this.maximumJacobiIterations;i++){ + offDiagonalSum = 0.0; + for(int p=0;p<this.numberOfRows-1;p++){ + for(int q=p+1;q<this.numberOfRows;q++){ + offDiagonalSum += Math.abs(amat[p][q]); + } + } + if(offDiagonalSum==0.0){ + this.eigenDone = true; + this.eigenSort(); + return; + } + if (i < 4){ + threshold = 0.2*offDiagonalSum/(this.numberOfRows*this.numberOfRows); + } + else{ + threshold = 0.0; + } + for(int p=0;p<this.numberOfRows-1;p++){ + for(int q=p+1;q<this.numberOfRows;q++){ + scaledOffDiagonal = 100.0*Math.abs(amat[p][q]); + if (i > 4 && (Math.abs(this.eigenValues[p]) + scaledOffDiagonal) == Math.abs(this.eigenValues[p]) && (Math.abs(this.eigenValues[q]) + scaledOffDiagonal) == Math.abs(this.eigenValues[q])){ + amat[p][q] = 0.0; + } + else if(Math.abs(amat[p][q]) > threshold){ + vectorDifference = this.eigenValues[q] - this.eigenValues[p]; + if ((Math.abs(vectorDifference) + scaledOffDiagonal) == Math.abs(vectorDifference)) + sOverC = amat[p][q]/vectorDifference; + else{ + cot2rotationAngle = 0.5*vectorDifference/amat[p][q]; + sOverC = 1.0/(Math.abs(cot2rotationAngle) + Math.sqrt(1.0 + cot2rotationAngle*cot2rotationAngle)); + if (cot2rotationAngle < 0.0) sOverC = -sOverC; + } + cElement = 1.0/Math.sqrt(1.0 + sOverC*sOverC); + sElement = sOverC*cElement; + tanHalfRotationAngle = sElement/(1.0 + cElement); + vectorDifference = sOverC*amat[p][q]; + holdingVector2[p] -= vectorDifference; + holdingVector2[q] += vectorDifference; + this.eigenValues[p] -= vectorDifference; + this.eigenValues[q] += vectorDifference; + amat[p][q] = 0.0; + for(int j=0;j<=p-1;j++) rotation(amat, tanHalfRotationAngle, sElement, j, p, j, q); + for(int j=p+1;j<=q-1;j++) rotation(amat, tanHalfRotationAngle, sElement, p, j, j, q); + for(int j=q+1;j<this.numberOfRows;j++) rotation(amat, tanHalfRotationAngle, sElement,p, j, q, j); + for(int j=0;j<this.numberOfRows;j++) rotation(this.eigenVector, tanHalfRotationAngle, sElement, j, p, j, q); + ++this.numberOfRotations; + } + } + } + for(int p=0;p<this.numberOfRows;p++){ + holdingVector1[p] += holdingVector2[p]; + this.eigenValues[p] = holdingVector1[p]; + holdingVector2[p] = 0.0; + } + } + System.out.println("Maximum iterations, " + this.maximumJacobiIterations + ", reached - values at this point returned"); + this.eigenDone = true; + this.eigenSort(); + } + + // matrix rotaion required by symmetricEigen + private void rotation(double[][] a, double tau, double sElement, int i, int j, int k, int l){ + double aHold1 = a[i][j]; + double aHold2 = a[k][l]; + a[i][j] = aHold1 - sElement*(aHold2 + aHold1*tau); + a[k][l] = aHold2 + sElement*(aHold1 - aHold2*tau); + } + + // Sorts eigen values into descending order and rearranges eigen vecors to match + // follows Numerical Recipes (see above) + private void eigenSort(){ + int k = 0; + double holdingElement; + this.sortedEigenValues = this.eigenValues.clone(); + this.sortedEigenVector = this.eigenVector.clone(); + this.eigenIndices = new int[this.numberOfRows]; + + for(int i=0; i<this.numberOfRows-1; i++){ + holdingElement = this.sortedEigenValues[i]; + k = i; + for(int j=i+1; j<this.numberOfRows; j++){ + if (this.sortedEigenValues[j] >= holdingElement){ + holdingElement = this.sortedEigenValues[j]; + k = j; + } + } + if (k != i){ + this.sortedEigenValues[k] = this.sortedEigenValues[i]; + this.sortedEigenValues[i] = holdingElement; + + for(int j=0; j<this.numberOfRows; j++){ + holdingElement = this.sortedEigenVector[j][i]; + this.sortedEigenVector[j][i] = this.sortedEigenVector[j][k]; + this.sortedEigenVector[j][k] = holdingElement; + } + } + } + this.eigenIndices = new int[this.numberOfRows]; + for(int i=0; i<this.numberOfRows; i++){ + boolean test = true; + int j = 0; + while(test){ + if(this.sortedEigenValues[i]==this.eigenValues[j]){ + this.eigenIndices[i] = j; + test = false; + } + else{ + j++; + } + } + } + } + + // Return indices of the eigen values before sorting into descending order + public int[] eigenValueIndices(){ + if(!this.eigenDone)symmetricEigen(); + return this.eigenIndices; + } + + + // Method not in java.lang.maths required in this Class + // See Fmath.class for public versions of this method + private static double hypot(double aa, double bb){ + double cc = 0.0D, ratio = 0.0D; + double amod=Math.abs(aa); + double bmod=Math.abs(bb); + + if(amod==0.0D){ + cc=bmod; + } + else{ + if(bmod==0.0D){ + cc=amod; + } + else{ + if(amod<=bmod){ + ratio=amod/bmod; + cc=bmod*Math.sqrt(1.0D+ratio*ratio); + } + else{ + ratio=bmod/amod; + cc=amod*Math.sqrt(1.0D+ratio*ratio); + } + } + } + return cc; + } + +} + + + + diff --git a/src/main/java/flanagan/math/Maximisation.java b/src/main/java/flanagan/math/Maximisation.java new file mode 100755 index 0000000000000000000000000000000000000000..7bcb00f30eb63027a39961e682511eaf97d0ef96 --- /dev/null +++ b/src/main/java/flanagan/math/Maximisation.java @@ -0,0 +1,1057 @@ +/* +* Class Maximisation +* +* Contains methods for finding the values of the +* function parameters that maximise that function +* using the Nelder and Mead Simplex method. +* +* The function needed by the maximisation method +* is supplied through the interface, MaximisationFunction +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 29 December 2005 (adapted from Minimisation) +* UPDATES: 28 December 2007, 10/12 May 2008, 4 July 2008, 28 July 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Maximisation.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2005 - 2008 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.math; + +import java.util.*; +import flanagan.math.Fmath; +import flanagan.io.FileOutput; + + +// Maximisation class +public class Maximisation{ + + protected boolean iseOption = true; // = true if minimis... spelling used + // = false if minimiz... spelling used + protected int nParam=0; // number of unknown parameters to be estimated + protected double[]paramValue = null; // function parameter values (returned at function maximum) + protected String[] paraName = null; // names of parameters, eg, c[0], c[1], c[2] . . . + protected double functValue = 0.0D; // current value of the function to be maximised + protected double lastFunctValNoCnstrnt=0.0D; // Last function value with no constraint penalty + protected double maximum = 0.0D; // value of the function to be maximised at the maximum + protected int prec = 4; // number of places to which double variables are truncated on output to text files + protected int field = 13; // field width on output to text files + protected boolean convStatus = false; // Status of maximisation on exiting maximisation method + // = true - convergence criterion was met + // = false - convergence criterion not met - current estimates returned + protected boolean suppressNoConvergenceMessage = false; // if true - suppress the print out of a message saying that convergence was not achieved. + protected int scaleOpt=0; // if = 0; no scaling of initial estimates + // if = 1; initial simplex estimates scaled to unity + // if = 2; initial estimates scaled by user provided values in scale[] + // (default = 0) + protected double[] scale = null; // values to scale initial estimate (see scaleOpt above) + protected boolean penalty = false; // true if single parameter penalty function is included + protected boolean sumPenalty = false; // true if multiple parameter penalty function is included + protected int nConstraints = 0; // number of single parameter constraints + protected int nSumConstraints = 0; // number of multiple parameter constraints + protected int maxConstraintIndex = -1; // maximum index of constrained parameter/s + protected ArrayList<Object> penalties = new ArrayList<Object>(); // method index, + // number of single parameter constraints, + // then repeated for each constraint: + // penalty parameter index, + // below or above constraint flag, + // constraint boundary value + protected ArrayList<Object> sumPenalties = new ArrayList<Object>(); // constraint method index, + // number of multiple parameter constraints, + // then repeated for each constraint: + // number of parameters in summation + // penalty parameter indices, + // summation signs + // below or above constraint flag, + // constraint boundary value + protected int[] penaltyCheck = null; // = -1 values below the single constraint boundary not allowed + // = +1 values above the single constraint boundary not allowed + protected int[] sumPenaltyCheck = null; // = -1 values below the multiple constraint boundary not allowed + // = +1 values above the multiple constraint boundary not allowed + protected double penaltyWeight = 1.0e30; // weight for the penalty functions + protected int[] penaltyParam = null; // indices of paramaters subject to single parameter constraint + protected int[][] sumPenaltyParam = null; // indices of paramaters subject to multiple parameter constraint + protected double[][] sumPlusOrMinus = null; // sign before each parameter in multiple parameter summation + protected int[] sumPenaltyNumber = null; // number of paramaters in each multiple parameter constraint + protected double constraintTolerance = 1e-4; // tolerance in constraining parameter/s to a fixed value + + protected double[] constraints = null; // single parameter constraint values + protected double[] sumConstraints = null; // multiple parameter constraint values + protected int constraintMethod = 0; // constraint method number + // =0: cliff to the power two (only method at present) + protected int nMax = 3000; // Nelder and Mead simplex maximum number of iterations + protected int nIter = 0; // Nelder and Mead simplex number of iterations performed + protected int konvge = 3; // Nelder and Mead simplex number of restarts allowed + protected int kRestart = 0; // Nelder and Mead simplex number of restarts taken + protected double fTol = 1e-13; // Nelder and Mead simplex convergence tolerance + protected double rCoeff = 1.0D; // Nelder and Mead simplex reflection coefficient + protected double eCoeff = 2.0D; // Nelder and Mead simplex extension coefficient + protected double cCoeff = 0.5D; // Nelder and Mead simplex contraction coefficient + protected double[] startH = null; // Nelder and Mead simplex initial estimates + protected double[] step = null; // Nelder and Mead simplex step values + protected double dStep = 0.5D; // Nelder and Mead simplex default step value + protected int maxTest = 0; // Nelder and Mead maximum test + // = 0; tests simplex sd < fTol + // allows options for further tests to be added later + protected double simplexSd = 0.0D; // simplex standard deviation + + + //Constructors + public Maximisation(){ + this.iseOption = true; + } + + // Suppress the print out of a message saying that convergence was not achieved. + public void suppressNoConvergenceMessage(){ + this.suppressNoConvergenceMessage = true; + } + + // Nelder and Mead Simplex maximization + public void nelderMead(MaximizationFunction gg, double[] start, double[] step, double fTol, int nMax){ + this.nelderMead((Object)gg, start, step, fTol, nMax); + } + + // Nelder and Mead Simplex maximization + public void nelderMead(MaximisationFunction gg, double[] start, double[] step, double fTol, int nMax){ + this.nelderMead((Object)gg, start, step, fTol, nMax); + } + + // Nelder and Mead Simplex maximization + public void nelderMead(Object g, double[] start, double[] step, double fTol, int nMax){ + boolean testContract=false; // test whether a simplex contraction has been performed + int np = start.length; // number of unknown parameters; + if(this.maxConstraintIndex>=np)throw new IllegalArgumentException("You have entered more constrained parameters ("+this.maxConstraintIndex+") than minimisation parameters (" + np + ")"); + this.nParam = np; + this.convStatus = true; + int nnp = np+1; // Number of simplex apices + this.lastFunctValNoCnstrnt=0.0D; + + if(this.scaleOpt<2)this.scale = new double[np]; + if(scaleOpt==2 && scale.length!=start.length)throw new IllegalArgumentException("scale array and initial estimate array are of different lengths"); + if(step.length!=start.length)throw new IllegalArgumentException("step array length " + step.length + " and initial estimate array length " + start.length + " are of different"); + + // check for zero step sizes + for(int i=0; i<np; i++)if(step[i]==0.0D)throw new IllegalArgumentException("step " + i+ " size is zero"); + + // set up arrays + this.paramValue = new double[np]; + this.startH = new double[np]; + this.step = new double[np]; + double[]pmax = new double[np]; //Nelder and Mead Pmax + + double[][] pp = new double[nnp][nnp]; //Nelder and Mead P + double[] yy = new double[nnp]; //Nelder and Mead y + double[] pbar = new double[nnp]; //Nelder and Mead P with bar superscript + double[] pstar = new double[nnp]; //Nelder and Mead P* + double[] p2star = new double[nnp]; //Nelder and Mead P** + + // Set any single parameter constraint parameters + if(this.penalty){ + Integer itemp = (Integer)this.penalties.get(1); + this.nConstraints = itemp.intValue(); + this.penaltyParam = new int[this.nConstraints]; + this.penaltyCheck = new int[this.nConstraints]; + this.constraints = new double[this.nConstraints]; + Double dtemp = null; + int j=2; + for(int i=0;i<this.nConstraints;i++){ + itemp = (Integer)this.penalties.get(j); + this.penaltyParam[i] = itemp.intValue(); + j++; + itemp = (Integer)this.penalties.get(j); + this.penaltyCheck[i] = itemp.intValue(); + j++; + dtemp = (Double)this.penalties.get(j); + this.constraints[i] = dtemp.doubleValue(); + j++; + } + } + + // Set any multiple parameter constraint parameters + if(this.sumPenalty){ + Integer itemp = (Integer)this.sumPenalties.get(1); + this.nSumConstraints = itemp.intValue(); + this.sumPenaltyParam = new int[this.nSumConstraints][]; + this.sumPlusOrMinus = new double[this.nSumConstraints][]; + this.sumPenaltyCheck = new int[this.nSumConstraints]; + this.sumPenaltyNumber = new int[this.nSumConstraints]; + this.sumConstraints = new double[this.nSumConstraints]; + int[] itempArray = null; + double[] dtempArray = null; + Double dtemp = null; + int j=2; + for(int i=0;i<this.nSumConstraints;i++){ + itemp = (Integer)this.sumPenalties.get(j); + this.sumPenaltyNumber[i] = itemp.intValue(); + j++; + itempArray = (int[])this.sumPenalties.get(j); + this.sumPenaltyParam[i] = itempArray; + j++; + dtempArray = (double[])this.sumPenalties.get(j); + this.sumPlusOrMinus[i] = dtempArray; + j++; + itemp = (Integer)this.sumPenalties.get(j); + this.sumPenaltyCheck[i] = itemp.intValue(); + j++; + dtemp = (Double)this.sumPenalties.get(j); + this.sumConstraints[i] = dtemp.doubleValue(); + j++; + } + } + + // Store unscaled start values + for(int i=0; i<np; i++)this.startH[i]=start[i]; + + // scale initial estimates and step sizes + if(this.scaleOpt>0){ + boolean testzero=false; + for(int i=0; i<np; i++)if(start[i]==0.0D)testzero=true; + if(testzero){ + System.out.println("Neler and Mead Simplex: a start value of zero precludes scaling"); + System.out.println("Regression performed without scaling"); + this.scaleOpt=0; + } + } + switch(this.scaleOpt){ + case 0: for(int i=0; i<np; i++)scale[i]=1.0D; + break; + case 1: for(int i=0; i<np; i++){ + scale[i]=1.0/start[i]; + step[i]=step[i]/start[i]; + start[i]=1.0D; + } + break; + case 2: for(int i=0; i<np; i++){ + step[i]*=scale[i]; + start[i]*= scale[i]; + } + break; + } + + // set class member values + this.fTol=fTol; + this.nMax=nMax; + this.nIter=0; + for(int i=0; i<np; i++){ + this.step[i]=step[i]; + this.scale[i]=scale[i]; + } + + // initial simplex + double sho=0.0D; + for (int i=0; i<np; ++i){ + sho=start[i]; + pstar[i]=sho; + p2star[i]=sho; + pmax[i]=sho; + } + + int jcount=this.konvge; // count of number of restarts still available + + for (int i=0; i<np; ++i){ + pp[i][nnp-1]=start[i]; + } + yy[nnp-1]=this.functionValue(g, start); + for (int j=0; j<np; ++j){ + start[j]=start[j]+step[j]; + + for (int i=0; i<np; ++i)pp[i][j]=start[i]; + yy[j]=this.functionValue(g, start); + start[j]=start[j]-step[j]; + } + + // loop over allowed iterations + double ynewlo=0.0D; // current value lowest y + double ystar = 0.0D; // Nelder and Mead y* + double y2star = 0.0D; // Nelder and Mead y** + double ylo = 0.0D; // Nelder and Mead y(low) + double fMax; // function value at maximum + // variables used in calculating the variance of the simplex at a putative maximum + double curMin = 00D, sumnm = 0.0D, summnm = 0.0D, zn = 0.0D; + int ilo=0; // index of low apex + int ihi=0; // index of high apex + int ln=0; // counter for a check on low and high apices + boolean test = true; // test becomes false on reaching maximum + + while(test){ + // Determine h + ylo=yy[0]; + ynewlo=ylo; + ilo=0; + ihi=0; + for (int i=1; i<nnp; ++i){ + if (yy[i]<ylo){ + ylo=yy[i]; + ilo=i; + } + if (yy[i]>ynewlo){ + ynewlo=yy[i]; + ihi=i; + } + } + // Calculate pbar + for (int i=0; i<np; ++i){ + zn=0.0D; + for (int j=0; j<nnp; ++j){ + zn += pp[i][j]; + } + zn -= pp[i][ihi]; + pbar[i] = zn/np; + } + + // Calculate p=(1+alpha).pbar-alpha.ph {Reflection} + for (int i=0; i<np; ++i)pstar[i]=(1.0 + this.rCoeff)*pbar[i]-this.rCoeff*pp[i][ihi]; + + // Calculate y* + ystar=this.functionValue(g, pstar); + + ++this.nIter; + + // check for y*<yi + if(ystar < ylo){ + // Form p**=(1+gamma).p*-gamma.pbar {Extension} + for (int i=0; i<np; ++i)p2star[i]=pstar[i]*(1.0D + this.eCoeff)-this.eCoeff*pbar[i]; + // Calculate y** + y2star=this.functionValue(g, p2star); + ++this.nIter; + if(y2star < ylo){ + // Replace ph by p** + for (int i=0; i<np; ++i)pp[i][ihi] = p2star[i]; + yy[ihi] = y2star; + } + else{ + //Replace ph by p* + for (int i=0; i<np; ++i)pp[i][ihi]=pstar[i]; + yy[ihi]=ystar; + } + } + else{ + // Check y*>yi, i!=h + ln=0; + for (int i=0; i<nnp; ++i)if (i!=ihi && ystar > yy[i]) ++ln; + if (ln==np ){ + // y*>= all yi; Check if y*>yh + if(ystar<=yy[ihi]){ + // Replace ph by p* + for (int i=0; i<np; ++i)pp[i][ihi]=pstar[i]; + yy[ihi]=ystar; + } + // Calculate p** =beta.ph+(1-beta)pbar {Contraction} + for (int i=0; i<np; ++i)p2star[i]=this.cCoeff*pp[i][ihi] + (1.0 - this.cCoeff)*pbar[i]; + // Calculate y** + y2star=this.functionValue(g, p2star); + ++this.nIter; + // Check if y**>yh + if(y2star>yy[ihi]){ + //Replace all pi by (pi+pl)/2 + + for (int j=0; j<nnp; ++j){ + for (int i=0; i<np; ++i){ + pp[i][j]=0.5*(pp[i][j] + pp[i][ilo]); + pmax[i]=pp[i][j]; + } + yy[j]=this.functionValue(g, pmax); + } + this.nIter += nnp; + } + else{ + // Replace ph by p** + for (int i=0; i<np; ++i)pp[i][ihi] = p2star[i]; + yy[ihi] = y2star; + } + } + else{ + // replace ph by p* + for (int i=0; i<np; ++i)pp[i][ihi]=pstar[i]; + yy[ihi]=ystar; + } + } + + // test for convergence + // calculte sd of simplex and maximum point + sumnm=0.0; + ynewlo=yy[0]; + ilo=0; + for (int i=0; i<nnp; ++i){ + sumnm += yy[i]; + if(ynewlo>yy[i]){ + ynewlo=yy[i]; + ilo=i; + } + } + sumnm /= (double)(nnp); + summnm=0.0; + for (int i=0; i<nnp; ++i){ + zn=yy[i]-sumnm; + summnm += zn*zn; + } + curMin=Math.sqrt(summnm/np); + + // test simplex sd + switch(this.maxTest){ + case 0: + if(curMin<fTol)test=false; + break; + } + this.maximum = -ynewlo; + if(!test){ + // store parameter values + for (int i=0; i<np; ++i)pmax[i]=pp[i][ilo]; + yy[nnp-1]=ynewlo; + // store simplex sd + this.simplexSd = curMin; + // test for restart + --jcount; + if(jcount>0){ + test=true; + for (int j=0; j<np; ++j){ + pmax[j]=pmax[j]+step[j]; + for (int i=0; i<np; ++i)pp[i][j]=pmax[i]; + yy[j]=this.functionValue(g, pmax); + pmax[j]=pmax[j]-step[j]; + } + } + } + + if(test && this.nIter>this.nMax){ + if(!this.suppressNoConvergenceMessage){ + System.out.println("Maximum iteration number reached, in Maximisation.simplex(...)"); + System.out.println("without the convergence criterion being satisfied"); + System.out.println("Current parameter estimates and function value returned"); + } + this.convStatus = false; + // store current estimates + for (int i=0; i<np; ++i)pmax[i]=pp[i][ilo]; + yy[nnp-1]=ynewlo; + test=false; + } + } + + for (int i=0; i<np; ++i){ + pmax[i] = pp[i][ilo]; + paramValue[i] = pmax[i]/this.scale[i]; + } + this.maximum = -ynewlo; + this.kRestart = this.konvge - jcount; + + } + + // Nelder and Mead simplex + // Default maximum iterations + public void nelderMead(MaximizationFunction g, double[] start, double[] step, double fTol){ + int nMaxx = this.nMax; + this.nelderMead(g, start, step, fTol, nMaxx); + } + + public void nelderMead(MaximisationFunction g, double[] start, double[] step, double fTol){ + int nMaxx = this.nMax; + this.nelderMead(g, start, step, fTol, nMaxx); + } + + // Nelder and Mead simplex + // Default tolerance + public void nelderMead(MaximizationFunction g, double[] start, double[] step, int nMax){ + double fToll = this.fTol; + this.nelderMead(g, start, step, fToll, nMax); + } + + public void nelderMead(MaximisationFunction g, double[] start, double[] step, int nMax){ + double fToll = this.fTol; + this.nelderMead(g, start, step, fToll, nMax); + } + + // Nelder and Mead simplex + // Default tolerance + // Default maximum iterations + public void nelderMead(MaximizationFunction g, double[] start, double[] step){ + double fToll = this.fTol; + int nMaxx = this.nMax; + this.nelderMead(g, start, step, fToll, nMaxx); + } + + public void nelderMead(MaximisationFunction g, double[] start, double[] step){ + double fToll = this.fTol; + int nMaxx = this.nMax; + this.nelderMead(g, start, step, fToll, nMaxx); + } + + // Nelder and Mead simplex + // Default step option - all step[i] = dStep + public void nelderMead(MaximizationFunction g, double[] start, double fTol, int nMax){ + int n=start.length; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fTol, nMax); + } + + public void nelderMead(MaximisationFunction g, double[] start, double fTol, int nMax){ + int n=start.length; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fTol, nMax); + } + + // Nelder and Mead simplex + // Default maximum iterations + // Default step option - all step[i] = dStep + public void nelderMead(MaximizationFunction g, double[] start, double fTol){ + int n=start.length; + int nMaxx = this.nMax; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fTol, nMaxx); + } + + public void nelderMead(MaximisationFunction g, double[] start, double fTol){ + int n=start.length; + int nMaxx = this.nMax; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fTol, nMaxx); + } + + // Nelder and Mead simplex + // Default tolerance + // Default step option - all step[i] = dStep + public void nelderMead(MaximizationFunction g, double[] start, int nMax){ + int n=start.length; + double fToll = this.fTol; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fToll, nMax); + } + + public void nelderMead(MaximisationFunction g, double[] start, int nMax){ + int n=start.length; + double fToll = this.fTol; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fToll, nMax); + } + + // Nelder and Mead simplex + // Default tolerance + // Default maximum iterations + // Default step option - all step[i] = dStep + public void nelderMead(MaximizationFunction g, double[] start){ + int n=start.length; + int nMaxx = this.nMax; + double fToll = this.fTol; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fToll, nMaxx); + } + + public void nelderMead(MaximisationFunction g, double[] start){ + int n=start.length; + int nMaxx = this.nMax; + double fToll = this.fTol; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fToll, nMaxx); + } + + // Calculate the function value for maximisation + protected double functionValue(Object g, double[] x){ + if(this.iseOption){ + return functionValue((MaximisationFunction) g, x); + } + else{ + return functionValue((MaximizationFunction) g, x); + } + } + + // Calculate the function value for maximisation + protected double functionValue(MaximizationFunction g, double[] x){ + double funcVal = -3.0D; + double[] param = new double[this.nParam]; + // rescale + for(int i=0; i<this.nParam; i++)param[i]=x[i]/scale[i]; + + // single parameter penalty functions + double tempFunctVal = this.lastFunctValNoCnstrnt; + boolean test=true; + if(this.penalty){ + int k=0; + for(int i=0; i<this.nConstraints; i++){ + k = this.penaltyParam[i]; + switch(penaltyCheck[i]){ + case -1: if(param[k]<constraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(constraints[i]-param[k]); + test=false; + } + break; + case 0: if(param[k]<constraints[i]*(1.0-this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(constraints[i]*(1.0-this.constraintTolerance)-param[k]); + test=false; + } + if(param[k]>constraints[i]*(1.0+this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(param[k]-constraints[i]*(1.0+this.constraintTolerance)); + test=false; + } + break; + case 1: if(param[k]>constraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(param[k]-constraints[i]); + test=false; + } + break; + } + } + } + + // multiple parameter penalty functions + if(this.sumPenalty){ + int kk = 0; + double pSign = 0; + double sumPenaltySum = 0.0D; + for(int i=0; i<this.nSumConstraints; i++){ + for(int j=0; j<this.sumPenaltyNumber[i]; j++){ + kk = this.sumPenaltyParam[i][j]; + pSign = this.sumPlusOrMinus[i][j]; + sumPenaltySum += param[kk]*pSign; + } + switch(this.sumPenaltyCheck[i]){ + case -1: if(sumPenaltySum<sumConstraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumConstraints[i]-sumPenaltySum); + test=false; + } + break; + case 0: if(sumPenaltySum<sumConstraints[i]*(1.0-this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumConstraints[i]*(1.0-this.constraintTolerance)-sumPenaltySum); + test=false; + } + if(sumPenaltySum>sumConstraints[i]*(1.0+this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumPenaltySum-sumConstraints[i]*(1.0+this.constraintTolerance)); + test=false; + } + break; + case 1: if(sumPenaltySum>sumConstraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumPenaltySum-sumConstraints[i]); + test=false; + } + break; + } + + } + } + + if(test){ + funcVal = -g.function(param); + this.lastFunctValNoCnstrnt = funcVal; + } + return funcVal; + } + + + // Calculate the function value for maximisation + protected double functionValue(MaximisationFunction g, double[] x){ + double funcVal = -3.0D; + double[] param = new double[this.nParam]; + // rescale + for(int i=0; i<this.nParam; i++)param[i]=x[i]/scale[i]; + + // single parameter penalty functions + double tempFunctVal = this.lastFunctValNoCnstrnt; + boolean test=true; + if(this.penalty){ + int k=0; + for(int i=0; i<this.nConstraints; i++){ + k = this.penaltyParam[i]; + switch(penaltyCheck[i]){ + case -1: if(param[k]<constraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(constraints[i]-param[k]); + test=false; + } + break; + case 0: if(param[k]<constraints[i]*(1.0-this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(constraints[i]*(1.0-this.constraintTolerance)-param[k]); + test=false; + } + if(param[k]>constraints[i]*(1.0+this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(param[k]-constraints[i]*(1.0+this.constraintTolerance)); + test=false; + } + break; + case 1: if(param[k]>constraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(param[k]-constraints[i]); + test=false; + } + break; + } + } + } + + // multiple parameter penalty functions + if(this.sumPenalty){ + int kk = 0; + double pSign = 0; + double sumPenaltySum = 0.0D; + for(int i=0; i<this.nSumConstraints; i++){ + for(int j=0; j<this.sumPenaltyNumber[i]; j++){ + kk = this.sumPenaltyParam[i][j]; + pSign = this.sumPlusOrMinus[i][j]; + sumPenaltySum += param[kk]*pSign; + } + switch(this.sumPenaltyCheck[i]){ + case -1: if(sumPenaltySum<sumConstraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumConstraints[i]-sumPenaltySum); + test=false; + } + break; + case 0: if(sumPenaltySum<sumConstraints[i]*(1.0-this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumConstraints[i]*(1.0-this.constraintTolerance)-sumPenaltySum); + test=false; + } + if(sumPenaltySum>sumConstraints[i]*(1.0+this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumPenaltySum-sumConstraints[i]*(1.0+this.constraintTolerance)); + test=false; + } + break; + case 1: if(sumPenaltySum>sumConstraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumPenaltySum-sumConstraints[i]); + test=false; + } + break; + } + + } + } + + if(test){ + funcVal = -g.function(param); + this.lastFunctValNoCnstrnt = funcVal; + } + return funcVal; + } + + // add a single parameter constraint boundary for the maximisation + public void addConstraint(int paramIndex, int conDir, double constraint){ + this.penalty=true; + // First element reserved for method number if other methods than 'cliff' are added later + if(this.penalties.isEmpty())this.penalties.add(new Integer(this.constraintMethod)); + + // add constraint + if(penalties.size()==1){ + this.penalties.add(new Integer(1)); + } + else{ + int nPC = ((Integer)this.penalties.get(1)).intValue(); + nPC++; + this.penalties.set(1, new Integer(nPC)); + } + this.penalties.add(new Integer(paramIndex)); + this.penalties.add(new Integer(conDir)); + this.penalties.add(new Double(constraint)); + if(paramIndex>this.maxConstraintIndex)this.maxConstraintIndex = paramIndex; + } + + // add a multiple parameter constraint boundary for the non-linear regression + public void addConstraint(int[] paramIndices, int[] plusOrMinus, int conDir, double constraint){ + ArrayMaths am = new ArrayMaths(plusOrMinus); + double[] dpom = am.getArray_as_double(); + addConstraint(paramIndices, dpom, conDir, constraint); + } + + // add a multiple parameter constraint boundary for the maximisation + public void addConstraint(int[] paramIndices, double[] plusOrMinus, int conDir, double constraint){ + int nCon = paramIndices.length; + int nPorM = plusOrMinus.length; + if(nCon!=nPorM)throw new IllegalArgumentException("num of parameters, " + nCon + ", does not equal number of parameter signs, " + nPorM); + this.sumPenalty=true; + // First element reserved for method number if other methods than 'cliff' are added later + if(this.sumPenalties.isEmpty())this.sumPenalties.add(new Integer(this.constraintMethod)); + + // add constraint + if(sumPenalties.size()==1){ + this.sumPenalties.add(new Integer(1)); + } + else{ + int nPC = ((Integer)this.sumPenalties.get(1)).intValue(); + nPC++; + this.sumPenalties.set(1, new Integer(nPC)); + } + this.sumPenalties.add(new Integer(nCon)); + this.sumPenalties.add(paramIndices); + this.sumPenalties.add(plusOrMinus); + this.sumPenalties.add(new Integer(conDir)); + this.sumPenalties.add(new Double(constraint)); + ArrayMaths am = new ArrayMaths(paramIndices); + int maxI = am.getMaximum_as_int(); + if(maxI>this.maxConstraintIndex)this.maxConstraintIndex = maxI; + } + + // Set constraint method + public void setConstraintMethod(int conMeth){ + this.constraintMethod = conMeth; + if(!this.penalties.isEmpty())this.penalties.set(0, new Integer(this.constraintMethod)); + } + + // remove all constraint boundaries for the maximisation + public void removeConstraints(){ + + // check if single parameter constraints already set + if(!this.penalties.isEmpty()){ + int m=this.penalties.size(); + + // remove single parameter constraints + for(int i=m-1; i>=0; i--){ + this.penalties.remove(i); + } + } + this.penalty = false; + this.nConstraints = 0; + + // check if mutiple parameter constraints already set + if(!this.sumPenalties.isEmpty()){ + int m=this.sumPenalties.size(); + + // remove multiple parameter constraints + for(int i=m-1; i>=0; i--){ + this.sumPenalties.remove(i); + } + } + this.sumPenalty = false; + this.nSumConstraints = 0; + this.maxConstraintIndex = -1; + } + + // Reset the tolerance used in a fixed value constraint + public void setConstraintTolerance(double tolerance){ + this.constraintTolerance = tolerance; + } + + // Print the results of the maximisation + // File name provided + // prec = truncation precision + public void print(String filename, int prec){ + this.prec = prec; + this.print(filename); + } + + // Print the results of the maximisation + // No file name provided + // prec = truncation precision + public void print(int prec){ + this.prec = prec; + String filename="MaximisationOutput.txt"; + this.print(filename); + } + + // Print the results of the maximisation + // File name provided + // prec = truncation precision + public void print(String filename){ + + if(filename.indexOf('.')==-1)filename = filename+".txt"; + FileOutput fout = new FileOutput(filename, 'n'); + fout.dateAndTimeln(filename); + fout.println(" "); + fout.println("Simplex maximisation, using the method of Nelder and Mead,"); + fout.println("of the function y = f(c[0], c[1], c[2] . . .)"); + this.paraName = new String[this.nParam]; + for(int i=0;i<this.nParam;i++)this.paraName[i]="c["+i+"]"; + + fout.println(); + if(!this.convStatus){ + fout.println("Convergence criterion was not satisfied"); + fout.println("The following results are the current estimates on exiting the maximisation method"); + fout.println(); + } + + fout.println("Value of parameters at the maximum"); + fout.println(" "); + + fout.printtab(" ", this.field); + fout.printtab("Value at", this.field); + fout.printtab("Initial", this.field); + fout.println("Initial"); + + fout.printtab(" ", this.field); + fout.printtab("maximium", this.field); + fout.printtab("estimate", this.field); + fout.println("step"); + + for(int i=0; i<this.nParam; i++){ + fout.printtab(this.paraName[i], this.field); + fout.printtab(Fmath.truncate(paramValue[i],this.prec), this.field); + fout.printtab(Fmath.truncate(this.startH[i],this.prec), this.field); + fout.println(Fmath.truncate(this.step[i],this.prec)); + } + fout.println(); + + fout.println(" "); + + fout.printtab("Number of paramaters"); + fout.println(this.nParam); + fout.printtab("Number of iterations taken"); + fout.println(this.nIter); + fout.printtab("Maximum number of iterations allowed"); + fout.println(this.nMax); + fout.printtab("Number of restarts taken"); + fout.println(this.kRestart); + fout.printtab("Maximum number of restarts allowed"); + fout.println(this.konvge); + fout.printtab("Standard deviation of the simplex at the maximum"); + fout.println(Fmath.truncate(this.simplexSd, this.prec)); + fout.printtab("Convergence tolerance"); + fout.println(this.fTol); + switch(maxTest){ + case 0: if(this.convStatus){ + fout.println("simplex sd < the tolerance"); + } + else{ + fout.println("NOTE!!! simplex sd > the tolerance"); + } + break; + } + fout.println(); + fout.println("End of file"); + fout.close(); + } + + // Print the results of the maximisation + // No file name provided + public void print(){ + String filename="MaximisationOutput.txt"; + this.print(filename); + } + + // Get the maximisation status + // true if convergence was achieved + // false if convergence not achieved before maximum number of iterations + // current values then returned + public boolean getConvStatus(){ + return this.convStatus; + } + + // Reset scaling factors (scaleOpt 0 and 1, see below for scaleOpt 2) + public void setScale(int n){ + if(n<0 || n>1)throw new IllegalArgumentException("The argument must be 0 (no scaling) 1(initial estimates all scaled to unity) or the array of scaling factors"); + this.scaleOpt=n; + } + + // Reset scaling factors (scaleOpt 2, see above for scaleOpt 0 and 1) + public void setScale(double[] sc){ + this.scale=sc; + this.scaleOpt=2; + } + + // Get scaling factors + public double[] getScale(){ + return this.scale; + } + + // Reset the maximisation convergence test option + public void setMaxTest(int n){ + if(n<0 || n>1)throw new IllegalArgumentException("maxTest must be 0 or 1"); + this.maxTest=n; + } + + // Get the maximisation convergence test option + public int getMaxTest(){ + return this.maxTest; + } + + // Get the simplex sd at the maximum + public double getSimplexSd(){ + return this.simplexSd; + } + + // Get the values of the parameters at the maximum + public double[] getParamValues(){ + return this.paramValue; + } + + // Get the function value at maximum + public double getMaximum(){ + return this.maximum; + } + + // Get the number of iterations in Nelder and Mead + public int getNiter(){ + return this.nIter; + } + + + // Set the maximum number of iterations allowed in Nelder and Mead + public void setNmax(int nmax){ + this.nMax = nmax; + } + + // Get the maximum number of iterations allowed in Nelder and Mead + public int getNmax(){ + return this.nMax; + } + + // Get the number of restarts in Nelder and Mead + public int getNrestarts(){ + return this.kRestart; + } + + // Set the maximum number of restarts allowed in Nelder and Mead + public void setNrestartsMax(int nrs){ + this.konvge = nrs; + } + + // Get the maximum number of restarts allowed in Nelder amd Mead + public int getNrestartsMax(){ + return this.konvge; + } + + // Reset the Nelder and Mead reflection coefficient [alpha] + public void setNMreflect(double refl){ + this.rCoeff = refl; + } + + // Get the Nelder and Mead reflection coefficient [alpha] + public double getNMreflect(){ + return this.rCoeff; + } + + // Reset the Nelder and Mead extension coefficient [beta] + public void setNMextend(double ext){ + this.eCoeff = ext; + } + // Get the Nelder and Mead extension coefficient [beta] + public double getNMextend(){ + return this.eCoeff; + } + + // Reset the Nelder and Mead contraction coefficient [gamma] + public void setNMcontract(double con){ + this.cCoeff = con; + } + + // Get the Nelder and Mead contraction coefficient [gamma] + public double getNMcontract(){ + return cCoeff; + } + + // Set the maximisation tolerance + public void setTolerance(double tol){ + this.fTol = tol; + } + + + // Get the maximisation tolerance + public double getTolerance(){ + return this.fTol; + } + +} diff --git a/src/main/java/flanagan/math/MaximisationFunction.java b/src/main/java/flanagan/math/MaximisationFunction.java new file mode 100755 index 0000000000000000000000000000000000000000..6865cc7ac6494fcbd1a70d2cc96c32956a786c23 --- /dev/null +++ b/src/main/java/flanagan/math/MaximisationFunction.java @@ -0,0 +1,38 @@ +/* +* Interface MaximisationFunction +* +* This interface provides the abstarct method for the function to be +* maximised by the methods in the class, Maximisation +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: April 2003 +* MODIFIED: April 2004 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Maximisation.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2008 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +****************************************************************************************/ + +package flanagan.math; + +// Interface for Maximisation class +// Calculates value of function to be maximised +public interface MaximisationFunction{ + + double function(double[]param); +} \ No newline at end of file diff --git a/src/main/java/flanagan/math/Maximization.java b/src/main/java/flanagan/math/Maximization.java new file mode 100755 index 0000000000000000000000000000000000000000..af911ab4a6f5d0581f257fcd36b1912d140b1364 --- /dev/null +++ b/src/main/java/flanagan/math/Maximization.java @@ -0,0 +1,51 @@ +/* +* Class Maximization +* IDENTICAL TO class Maximisation - created simply to accommodate alternate spelling +* +* Contains methods for finding the values of the +* function parameters that maximize that function +* using the Nelder and Mead Simplex method. +* +* The function needed by the maximization method +* is supplied through the interface, MaximizationFunction +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 29 December 2005 (adapted from Minimisation) +* UPDATES: 28 December 2007, 10/12 May 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Maximisation.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2005 - 2008 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.math; + +import java.util.*; +import flanagan.math.Fmath; +import flanagan.io.FileOutput; + + +// Maximization class +public class Maximization extends Maximisation{ + + //Constructors + public Maximization(){ + super(); + this.iseOption = false; + } +} diff --git a/src/main/java/flanagan/math/MaximizationFunction.java b/src/main/java/flanagan/math/MaximizationFunction.java new file mode 100755 index 0000000000000000000000000000000000000000..74a59812b3a0cf099cbe7fc65185b9713abc6ec3 --- /dev/null +++ b/src/main/java/flanagan/math/MaximizationFunction.java @@ -0,0 +1,38 @@ +/* +* Interface MaximizationFunction +* +* This interface provides the abstarct method for the function to be +* maximized by the methods in the class, Maximization +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 12 May 2008 to match maximisationFunction (April 2003) + +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Maximisation.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2008 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +****************************************************************************************/ + +package flanagan.math; + +// Interface for Maximization class +// Calculates value of function to be maximized +public interface MaximizationFunction{ + + double function(double[]param); +} \ No newline at end of file diff --git a/src/main/java/flanagan/math/Minimisation.java b/src/main/java/flanagan/math/Minimisation.java new file mode 100755 index 0000000000000000000000000000000000000000..93683e538f8a3f767610ece82d3fab791b83b401 --- /dev/null +++ b/src/main/java/flanagan/math/Minimisation.java @@ -0,0 +1,1068 @@ +/* +* Class Minimisation +* +* Contains methods for finding the values of the +* function parameters that minimise that function +* using the Nelder and Mead Simplex method. +* +* The function needed by the minimisation method +* is supplied by though the interface, MinimisationFunction or Minimization +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: April 2003 +* MODIFIED: 29 December 2005, 18 February 2006, 28 December 2007, 10/12 May 2008, 4 July 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Minimisation.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2008 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.math; + +import java.util.*; +import flanagan.math.Fmath; +import flanagan.io.FileOutput; + + +// Minimisation class +public class Minimisation{ + + protected boolean iseOption = true; // = true if minimis... spelling used + // = false if minimiz... spelling used + protected int nParam=0; // number of unknown parameters to be estimated + protected double[]paramValue = null; // function parameter values (returned at function minimum) + protected String[] paraName = null; // names of parameters, eg, c[0], c[1], c[2] . . . + protected double functValue = 0.0D; // current value of the function to be minimised + protected double lastFunctValNoCnstrnt=0.0D;// Last function value with no constraint penalty + protected double minimum = 0.0D; // value of the function to be minimised at the minimum + protected int prec = 4; // number of places to which double variables are truncated on output to text files + protected int field = 13; // field width on output to text files + protected boolean convStatus = false; // Status of minimisation on exiting minimisation method + // = true - convergence criterion was met + // = false - convergence criterion not met - current estimates returned + protected boolean suppressNoConvergenceMessage = false; // if true - suppress the print out of a message saying that convergence was not achieved. + protected int scaleOpt=0; // if = 0; no scaling of initial estimates + // if = 1; initial simplex estimates scaled to unity + // if = 2; initial estimates scaled by user provided values in scale[] + // (default = 0) + protected double[] scale = null; // values to scale initial estimate (see scaleOpt above) + protected boolean penalty = false; // true if single parameter penalty function is included + protected boolean sumPenalty = false; // true if multiple parameter penalty function is included + protected int nConstraints = 0; // number of single parameter constraints + protected int nSumConstraints = 0; // number of multiple parameter constraints + protected int maxConstraintIndex = -1; // maximum index of constrained parameter/s + protected ArrayList<Object> penalties = new ArrayList<Object>(); // method index, + // number of single parameter constraints, + // then repeated for each constraint: + // penalty parameter index, + // below or above constraint flag, + // constraint boundary value + protected ArrayList<Object> sumPenalties = new ArrayList<Object>(); // constraint method index, + // number of multiple parameter constraints, + // then repeated for each constraint: + // number of parameters in summation + // penalty parameter indices, + // summation signs + // below or above constraint flag, + // constraint boundary value + protected int[] penaltyCheck = null; // = -1 values below the single constraint boundary not allowed + // = +1 values above the single constraint boundary not allowed + protected int[] sumPenaltyCheck = null; // = -1 values below the multiple constraint boundary not allowed + // = +1 values above the multiple constraint boundary not allowed + protected double penaltyWeight = 1.0e30; // weight for the penalty functions + protected int[] penaltyParam = null; // indices of paramaters subject to single parameter constraint + protected int[][] sumPenaltyParam = null; // indices of paramaters subject to multiple parameter constraint + protected double[][] sumPlusOrMinus = null; // value before each parameter in multiple parameter summation + protected int[] sumPenaltyNumber = null; // number of paramaters in each multiple parameter constraint + + protected double[] constraints = null; // single parameter constraint values + protected double constraintTolerance = 1e-4; // tolerance in constraining parameter/s to a fixed value + protected double[] sumConstraints = null; // multiple parameter constraint values + protected int constraintMethod = 0; // constraint method number + // =0: cliff to the power two (only method at present) + protected int nMax = 3000; // Nelder and Mead simplex maximum number of iterations + protected int nIter = 0; // Nelder and Mead simplex number of iterations performed + protected int konvge = 3; // Nelder and Mead simplex number of restarts allowed + protected int kRestart = 0; // Nelder and Mead simplex number of restarts taken + protected double fTol = 1e-13; // Nelder and Mead simplex convergence tolerance + protected double rCoeff = 1.0D; // Nelder and Mead simplex reflection coefficient + protected double eCoeff = 2.0D; // Nelder and Mead simplex extension coefficient + protected double cCoeff = 0.5D; // Nelder and Mead simplex contraction coefficient + protected double[] startH = null; // Nelder and Mead simplex initial estimates + protected double[] step = null; // Nelder and Mead simplex step values + protected double dStep = 0.5D; // Nelder and Mead simplex default step value + protected int minTest = 0; // Nelder and Mead minimum test + // = 0; tests simplex sd < fTol + // allows options for further tests to be added later + protected double simplexSd = 0.0D; // simplex standard deviation + + + //Constructor + public Minimisation(){ + this.iseOption = true; + } + + // Suppress the print out of a message saying that convergence was not achieved. + public void suppressNoConvergenceMessage(){ + this.suppressNoConvergenceMessage = true; + } + + // Suppress the print out of a message saying that convergence was not achieved. + public void supressNoConvergenceMessage(){ + this.suppressNoConvergenceMessage = true; + } + + // Nelder and Mead Simplex minimisation + public void nelderMead(MinimisationFunction gg, double[] start, double[] step, double fTol, int nMax){ + Object g = (Object)gg; + this.nelderMead(g, start, step, fTol, nMax); + } + + // Nelder and Mead Simplex minimisation + public void nelderMead(MinimizationFunction gg, double[] start, double[] step, double fTol, int nMax){ + Object g = (Object)gg; + this.nelderMead(g, start, step, fTol, nMax); + } + + // Nelder and Mead Simplex minimisation + public void nelderMead(Object g, double[] start, double[] step, double fTol, int nMax){ + + boolean testContract=false; // test whether a simplex contraction has been performed + int np = start.length; // number of unknown parameters; + if(this.maxConstraintIndex>=np)throw new IllegalArgumentException("You have entered more constrained parameters ("+this.maxConstraintIndex+") than minimisation parameters (" + np + ")"); + this.nParam = np; + this.convStatus = true; + int nnp = np+1; // Number of simplex apices + this.lastFunctValNoCnstrnt=0.0D; + + if(this.scaleOpt<2)this.scale = new double[np]; + if(scaleOpt==2 && scale.length!=start.length)throw new IllegalArgumentException("scale array and initial estimate array are of different lengths"); + if(step.length!=start.length)throw new IllegalArgumentException("step array length " + step.length + " and initial estimate array length " + start.length + " are of different"); + + // check for zero step sizes + for(int i=0; i<np; i++)if(step[i]==0.0D)throw new IllegalArgumentException("step " + i+ " size is zero"); + + // set up arrays + this.paramValue = new double[np]; + this.startH = new double[np]; + this.step = new double[np]; + double[]pmin = new double[np]; //Nelder and Mead Pmin + + double[][] pp = new double[nnp][nnp]; //Nelder and Mead P + double[] yy = new double[nnp]; //Nelder and Mead y + double[] pbar = new double[nnp]; //Nelder and Mead P with bar superscript + double[] pstar = new double[nnp]; //Nelder and Mead P* + double[] p2star = new double[nnp]; //Nelder and Mead P** + + // Set any single parameter constraint parameters + if(this.penalty){ + Integer itemp = (Integer)this.penalties.get(1); + this.nConstraints = itemp.intValue(); + this.penaltyParam = new int[this.nConstraints]; + this.penaltyCheck = new int[this.nConstraints]; + this.constraints = new double[this.nConstraints]; + Double dtemp = null; + int j=2; + for(int i=0;i<this.nConstraints;i++){ + itemp = (Integer)this.penalties.get(j); + this.penaltyParam[i] = itemp.intValue(); + j++; + itemp = (Integer)this.penalties.get(j); + this.penaltyCheck[i] = itemp.intValue(); + j++; + dtemp = (Double)this.penalties.get(j); + this.constraints[i] = dtemp.doubleValue(); + j++; + } + } + + // Set any multiple parameter constraint parameters + if(this.sumPenalty){ + Integer itemp = (Integer)this.sumPenalties.get(1); + this.nSumConstraints = itemp.intValue(); + this.sumPenaltyParam = new int[this.nSumConstraints][]; + this.sumPlusOrMinus = new double[this.nSumConstraints][]; + this.sumPenaltyCheck = new int[this.nSumConstraints]; + this.sumPenaltyNumber = new int[this.nSumConstraints]; + this.sumConstraints = new double[this.nSumConstraints]; + int[] itempArray = null; + double[] dtempArray = null; + Double dtemp = null; + int j=2; + for(int i=0;i<this.nSumConstraints;i++){ + itemp = (Integer)this.sumPenalties.get(j); + this.sumPenaltyNumber[i] = itemp.intValue(); + j++; + itempArray = (int[])this.sumPenalties.get(j); + this.sumPenaltyParam[i] = itempArray; + j++; + dtempArray = (double[])this.sumPenalties.get(j); + this.sumPlusOrMinus[i] = dtempArray; + j++; + itemp = (Integer)this.sumPenalties.get(j); + this.sumPenaltyCheck[i] = itemp.intValue(); + j++; + dtemp = (Double)this.sumPenalties.get(j); + this.sumConstraints[i] = dtemp.doubleValue(); + j++; + } + } + + // Store unscaled start values + for(int i=0; i<np; i++)this.startH[i]=start[i]; + + // scale initial estimates and step sizes + if(this.scaleOpt>0){ + boolean testzero=false; + for(int i=0; i<np; i++)if(start[i]==0.0D)testzero=true; + if(testzero){ + System.out.println("Neler and Mead Simplex: a start value of zero precludes scaling"); + System.out.println("Regression performed without scaling"); + this.scaleOpt=0; + } + } + switch(this.scaleOpt){ + case 0: for(int i=0; i<np; i++)scale[i]=1.0D; + break; + case 1: for(int i=0; i<np; i++){ + scale[i]=1.0/start[i]; + step[i]=step[i]/start[i]; + start[i]=1.0D; + } + break; + case 2: for(int i=0; i<np; i++){ + step[i]*=scale[i]; + start[i]*= scale[i]; + } + break; + } + + // set class member values + this.fTol=fTol; + this.nMax=nMax; + this.nIter=0; + for(int i=0; i<np; i++){ + this.step[i]=step[i]; + this.scale[i]=scale[i]; + } + + // initial simplex + double sho=0.0D; + for (int i=0; i<np; ++i){ + sho=start[i]; + pstar[i]=sho; + p2star[i]=sho; + pmin[i]=sho; + } + + int jcount=this.konvge; // count of number of restarts still available + + for (int i=0; i<np; ++i){ + pp[i][nnp-1]=start[i]; + } + yy[nnp-1]=this.functionValue(g, start); + for (int j=0; j<np; ++j){ + start[j]=start[j]+step[j]; + + for (int i=0; i<np; ++i)pp[i][j]=start[i]; + yy[j]=this.functionValue(g, start); + start[j]=start[j]-step[j]; + } + + // loop over allowed iterations + double ynewlo=0.0D; // current value lowest y + double ystar = 0.0D; // Nelder and Mead y* + double y2star = 0.0D; // Nelder and Mead y** + double ylo = 0.0D; // Nelder and Mead y(low) + double fMin; // function value at minimum + // variables used in calculating the variance of the simplex at a putative minimum + double curMin = 00D, sumnm = 0.0D, summnm = 0.0D, zn = 0.0D; + int ilo=0; // index of low apex + int ihi=0; // index of high apex + int ln=0; // counter for a check on low and high apices + boolean test = true; // test becomes false on reaching minimum + + while(test){ + // Determine h + ylo=yy[0]; + ynewlo=ylo; + ilo=0; + ihi=0; + for (int i=1; i<nnp; ++i){ + if (yy[i]<ylo){ + ylo=yy[i]; + ilo=i; + } + if (yy[i]>ynewlo){ + ynewlo=yy[i]; + ihi=i; + } + } + // Calculate pbar + for (int i=0; i<np; ++i){ + zn=0.0D; + for (int j=0; j<nnp; ++j){ + zn += pp[i][j]; + } + zn -= pp[i][ihi]; + pbar[i] = zn/np; + } + + // Calculate p=(1+alpha).pbar-alpha.ph {Reflection} + for (int i=0; i<np; ++i)pstar[i]=(1.0 + this.rCoeff)*pbar[i]-this.rCoeff*pp[i][ihi]; + + // Calculate y* + ystar=this.functionValue(g, pstar); + + ++this.nIter; + + // check for y*<yi + if(ystar < ylo){ + // Form p**=(1+gamma).p*-gamma.pbar {Extension} + for (int i=0; i<np; ++i)p2star[i]=pstar[i]*(1.0D + this.eCoeff)-this.eCoeff*pbar[i]; + // Calculate y** + y2star=this.functionValue(g, p2star); + ++this.nIter; + if(y2star < ylo){ + // Replace ph by p** + for (int i=0; i<np; ++i)pp[i][ihi] = p2star[i]; + yy[ihi] = y2star; + } + else{ + //Replace ph by p* + for (int i=0; i<np; ++i)pp[i][ihi]=pstar[i]; + yy[ihi]=ystar; + } + } + else{ + // Check y*>yi, i!=h + ln=0; + for (int i=0; i<nnp; ++i)if (i!=ihi && ystar > yy[i]) ++ln; + if (ln==np ){ + // y*>= all yi; Check if y*>yh + if(ystar<=yy[ihi]){ + // Replace ph by p* + for (int i=0; i<np; ++i)pp[i][ihi]=pstar[i]; + yy[ihi]=ystar; + } + // Calculate p** =beta.ph+(1-beta)pbar {Contraction} + for (int i=0; i<np; ++i)p2star[i]=this.cCoeff*pp[i][ihi] + (1.0 - this.cCoeff)*pbar[i]; + // Calculate y** + y2star=this.functionValue(g, p2star); + ++this.nIter; + // Check if y**>yh + if(y2star>yy[ihi]){ + //Replace all pi by (pi+pl)/2 + + for (int j=0; j<nnp; ++j){ + for (int i=0; i<np; ++i){ + pp[i][j]=0.5*(pp[i][j] + pp[i][ilo]); + pmin[i]=pp[i][j]; + } + yy[j]=this.functionValue(g, pmin); + } + this.nIter += nnp; + } + else{ + // Replace ph by p** + for (int i=0; i<np; ++i)pp[i][ihi] = p2star[i]; + yy[ihi] = y2star; + } + } + else{ + // replace ph by p* + for (int i=0; i<np; ++i)pp[i][ihi]=pstar[i]; + yy[ihi]=ystar; + } + } + + // test for convergence + // calculte sd of simplex and minimum point + sumnm=0.0; + ynewlo=yy[0]; + ilo=0; + for (int i=0; i<nnp; ++i){ + sumnm += yy[i]; + if(ynewlo>yy[i]){ + ynewlo=yy[i]; + ilo=i; + } + } + sumnm /= (double)(nnp); + summnm=0.0; + for (int i=0; i<nnp; ++i){ + zn=yy[i]-sumnm; + summnm += zn*zn; + } + curMin=Math.sqrt(summnm/np); + + // test simplex sd + switch(this.minTest){ + case 0: + if(curMin<fTol)test=false; + break; + } + this.minimum=ynewlo; + if(!test){ + // store parameter values + for (int i=0; i<np; ++i)pmin[i]=pp[i][ilo]; + yy[nnp-1]=ynewlo; + // store simplex sd + this.simplexSd = curMin; + // test for restart + --jcount; + if(jcount>0){ + test=true; + for (int j=0; j<np; ++j){ + pmin[j]=pmin[j]+step[j]; + for (int i=0; i<np; ++i)pp[i][j]=pmin[i]; + yy[j]=this.functionValue(g, pmin); + pmin[j]=pmin[j]-step[j]; + } + } + } + + if(test && this.nIter>this.nMax){ + if(!this.suppressNoConvergenceMessage){ + System.out.println("Maximum iteration number reached, in Minimisation.simplex(...)"); + System.out.println("without the convergence criterion being satisfied"); + System.out.println("Current parameter estimates and function value returned"); + } + this.convStatus = false; + // store current estimates + for (int i=0; i<np; ++i)pmin[i]=pp[i][ilo]; + yy[nnp-1]=ynewlo; + test=false; + } + } + + for (int i=0; i<np; ++i){ + pmin[i] = pp[i][ilo]; + paramValue[i] = pmin[i]/this.scale[i]; + } + this.minimum=ynewlo; + this.kRestart=this.konvge-jcount; + + } + + // Nelder and Mead simplex + // Default maximum iterations + public void nelderMead(MinimisationFunction g, double[] start, double[] step, double fTol){ + int nMaxx = this.nMax; + this.nelderMead(g, start, step, fTol, nMaxx); + } + + public void nelderMead(MinimizationFunction g, double[] start, double[] step, double fTol){ + int nMaxx = this.nMax; + this.nelderMead(g, start, step, fTol, nMaxx); + } + + // Nelder and Mead simplex + // Default tolerance + public void nelderMead(MinimisationFunction g, double[] start, double[] step, int nMax){ + double fToll = this.fTol; + this.nelderMead(g, start, step, fToll, nMax); + } + + public void nelderMead(MinimizationFunction g, double[] start, double[] step, int nMax){ + double fToll = this.fTol; + this.nelderMead(g, start, step, fToll, nMax); + } + + // Nelder and Mead simplex + // Default tolerance + // Default maximum iterations + public void nelderMead(MinimisationFunction g, double[] start, double[] step){ + double fToll = this.fTol; + int nMaxx = this.nMax; + this.nelderMead(g, start, step, fToll, nMaxx); + } + + public void nelderMead(MinimizationFunction g, double[] start, double[] step){ + double fToll = this.fTol; + int nMaxx = this.nMax; + this.nelderMead(g, start, step, fToll, nMaxx); + } + + // Nelder and Mead simplex + // Default step option - all step[i] = dStep + public void nelderMead(MinimisationFunction g, double[] start, double fTol, int nMax){ + int n=start.length; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fTol, nMax); + } + + public void nelderMead(MinimizationFunction g, double[] start, double fTol, int nMax){ + int n=start.length; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fTol, nMax); + } + + // Nelder and Mead simplex + // Default maximum iterations + // Default step option - all step[i] = dStep + public void nelderMead(MinimisationFunction g, double[] start, double fTol){ + int n=start.length; + int nMaxx = this.nMax; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fTol, nMaxx); + } + + public void nelderMead(MinimizationFunction g, double[] start, double fTol){ + int n=start.length; + int nMaxx = this.nMax; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fTol, nMaxx); + } + + // Nelder and Mead simplex + // Default tolerance + // Default step option - all step[i] = dStep + public void nelderMead(MinimisationFunction g, double[] start, int nMax){ + int n=start.length; + double fToll = this.fTol; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fToll, nMax); + } + + public void nelderMead(MinimizationFunction g, double[] start, int nMax){ + int n=start.length; + double fToll = this.fTol; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fToll, nMax); + } + + // Nelder and Mead simplex + // Default tolerance + // Default maximum iterations + // Default step option - all step[i] = dStep + public void nelderMead(MinimisationFunction g, double[] start){ + int n=start.length; + int nMaxx = this.nMax; + double fToll = this.fTol; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fToll, nMaxx); + } + + public void nelderMead(MinimizationFunction g, double[] start){ + int n=start.length; + int nMaxx = this.nMax; + double fToll = this.fTol; + double[] stepp = new double[n]; + for(int i=0; i<n;i++)stepp[i]=this.dStep*start[i]; + this.nelderMead(g, start, stepp, fToll, nMaxx); + } + + + // Calculate the function value for minimisation + protected double functionValue(Object g, double[] x){ + if(this.iseOption){ + return functionValue((MinimisationFunction) g, x); + } + else{ + return functionValue((MinimizationFunction) g, x); + } + } + + + // Calculate the function value for minimisation + protected double functionValue(MinimisationFunction g, double[] x){ + double funcVal = -3.0D; + double[] param = new double[this.nParam]; + // rescale + for(int i=0; i<this.nParam; i++)param[i]=x[i]/scale[i]; + + // single parameter penalty functions + double tempFunctVal = this.lastFunctValNoCnstrnt; + boolean test=true; + if(this.penalty){ + int k=0; + for(int i=0; i<this.nConstraints; i++){ + k = this.penaltyParam[i]; + switch(penaltyCheck[i]){ + case -1: if(param[k]<constraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(constraints[i]-param[k]); + test=false; + } + break; + case 0: if(param[k]<constraints[i]*(1.0-this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(constraints[i]*(1.0-this.constraintTolerance)-param[k]); + test=false; + } + if(param[k]>constraints[i]*(1.0+this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(param[k]-constraints[i]*(1.0+this.constraintTolerance)); + test=false; + } + break; + case 1: if(param[k]>constraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(param[k]-constraints[i]); + test=false; + } + break; + } + } + } + + // multiple parameter penalty functions + if(this.sumPenalty){ + int kk = 0; + double pSign = 0; + double sumPenaltySum = 0.0D; + for(int i=0; i<this.nSumConstraints; i++){ + for(int j=0; j<this.sumPenaltyNumber[i]; j++){ + kk = this.sumPenaltyParam[i][j]; + pSign = this.sumPlusOrMinus[i][j]; + sumPenaltySum += param[kk]*pSign; + } + switch(this.sumPenaltyCheck[i]){ + case -1: if(sumPenaltySum<sumConstraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumConstraints[i]-sumPenaltySum); + test=false; + } + break; + case 0: if(sumPenaltySum<sumConstraints[i]*(1.0-this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumConstraints[i]*(1.0-this.constraintTolerance)-sumPenaltySum); + test=false; + } + if(sumPenaltySum>sumConstraints[i]*(1.0+this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumPenaltySum-sumConstraints[i]*(1.0+this.constraintTolerance)); + test=false; + } + break; + case 1: if(sumPenaltySum>sumConstraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumPenaltySum-sumConstraints[i]); + test=false; + } + break; + } + } + } + + if(test){ + funcVal = g.function(param); + this.lastFunctValNoCnstrnt = funcVal; + } + return funcVal; + } + + + // Calculate the function value for minimisation + protected double functionValue(MinimizationFunction g, double[] x){ + double funcVal = -3.0D; + double[] param = new double[this.nParam]; + // rescale + for(int i=0; i<this.nParam; i++)param[i]=x[i]/scale[i]; + + // single parameter penalty functions + double tempFunctVal = this.lastFunctValNoCnstrnt; + boolean test=true; + if(this.penalty){ + int k=0; + for(int i=0; i<this.nConstraints; i++){ + k = this.penaltyParam[i]; + switch(penaltyCheck[i]){ + case -1: if(param[k]<constraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(constraints[i]-param[k]); + test=false; + } + break; + case 0: if(param[k]<constraints[i]*(1.0-this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(constraints[i]*(1.0-this.constraintTolerance)-param[k]); + test=false; + } + if(param[k]>constraints[i]*(1.0+this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(param[k]-constraints[i]*(1.0+this.constraintTolerance)); + test=false; + } + break; + case 1: if(param[k]>constraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(param[k]-constraints[i]); + test=false; + } + break; + } + } + } + + // multiple parameter penalty functions + if(this.sumPenalty){ + int kk = 0; + double pSign = 0; + double sumPenaltySum = 0.0D; + for(int i=0; i<this.nSumConstraints; i++){ + for(int j=0; j<this.sumPenaltyNumber[i]; j++){ + kk = this.sumPenaltyParam[i][j]; + pSign = this.sumPlusOrMinus[i][j]; + sumPenaltySum += param[kk]*pSign; + } + switch(this.sumPenaltyCheck[i]){ + case -1: if(sumPenaltySum<sumConstraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumConstraints[i]-sumPenaltySum); + test=false; + } + break; + case 0: if(sumPenaltySum<sumConstraints[i]*(1.0-this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumConstraints[i]*(1.0-this.constraintTolerance)-sumPenaltySum); + test=false; + } + if(sumPenaltySum>sumConstraints[i]*(1.0+this.constraintTolerance)){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumPenaltySum-sumConstraints[i]*(1.0+this.constraintTolerance)); + test=false; + } + break; + case 1: if(sumPenaltySum>sumConstraints[i]){ + funcVal = tempFunctVal + this.penaltyWeight*Fmath.square(sumPenaltySum-sumConstraints[i]); + test=false; + } + break; + } + } + } + + if(test){ + funcVal = g.function(param); + this.lastFunctValNoCnstrnt = funcVal; + } + return funcVal; + } + + + + // add a single parameter constraint boundary for the minimisation + public void addConstraint(int paramIndex, int conDir, double constraint){ + this.penalty=true; + // First element reserved for method number if other methods than 'cliff' are added later + if(this.penalties.isEmpty())this.penalties.add(new Integer(this.constraintMethod)); + + // add constraint + if(penalties.size()==1){ + this.penalties.add(new Integer(1)); + } + else{ + int nPC = ((Integer)this.penalties.get(1)).intValue(); + nPC++; + this.penalties.set(1, new Integer(nPC)); + } + this.penalties.add(new Integer(paramIndex)); + this.penalties.add(new Integer(conDir)); + this.penalties.add(new Double(constraint)); + if(paramIndex>this.maxConstraintIndex)this.maxConstraintIndex = paramIndex; + + } + + // add a multiple parameter constraint boundary for the non-linear regression + public void addConstraint(int[] paramIndices, int[] plusOrMinus, int conDir, double constraint){ + ArrayMaths am = new ArrayMaths(plusOrMinus); + double[] dpom = am.getArray_as_double(); + addConstraint(paramIndices, dpom, conDir, constraint); + } + + // add a multiple parameter constraint boundary for the minimisation + public void addConstraint(int[] paramIndices, double[] plusOrMinus, int conDir, double constraint){ + int nCon = paramIndices.length; + int nPorM = plusOrMinus.length; + if(nCon!=nPorM)throw new IllegalArgumentException("num of parameters, " + nCon + ", does not equal number of parameter signs, " + nPorM); + this.sumPenalty=true; + // First element reserved for method number if other methods than 'cliff' are added later + if(this.sumPenalties.isEmpty())this.sumPenalties.add(new Integer(this.constraintMethod)); + + // add constraint + if(sumPenalties.size()==1){ + this.sumPenalties.add(new Integer(1)); + } + else{ + int nPC = ((Integer)this.sumPenalties.get(1)).intValue(); + nPC++; + this.sumPenalties.set(1, new Integer(nPC)); + } + this.sumPenalties.add(new Integer(nCon)); + this.sumPenalties.add(paramIndices); + this.sumPenalties.add(plusOrMinus); + this.sumPenalties.add(new Integer(conDir)); + this.sumPenalties.add(new Double(constraint)); + ArrayMaths am = new ArrayMaths(paramIndices); + int maxI = am.getMaximum_as_int(); + if(maxI>this.maxConstraintIndex)this.maxConstraintIndex = maxI; + } + + // Set constraint method + public void setConstraintMethod(int conMeth){ + this.constraintMethod = conMeth; + if(!this.penalties.isEmpty())this.penalties.set(0, new Integer(this.constraintMethod)); + } + + // remove all constraint boundaries for the minimisation + public void removeConstraints(){ + + // check if single parameter constraints already set + if(!this.penalties.isEmpty()){ + int m=this.penalties.size(); + + // remove single parameter constraints + for(int i=m-1; i>=0; i--){ + this.penalties.remove(i); + } + } + this.penalty = false; + this.nConstraints = 0; + + // check if mutiple parameter constraints already set + if(!this.sumPenalties.isEmpty()){ + int m=this.sumPenalties.size(); + + // remove multiple parameter constraints + for(int i=m-1; i>=0; i--){ + this.sumPenalties.remove(i); + } + } + this.sumPenalty = false; + this.nSumConstraints = 0; + this.maxConstraintIndex = -1; + } + + // Reset the tolerance used in a fixed value constraint + public void setConstraintTolerance(double tolerance){ + this.constraintTolerance = tolerance; + } + + // Print the results of the minimisation + // File name provided + // prec = truncation precision + public void print(String filename, int prec){ + this.prec = prec; + this.print(filename); + } + + // Print the results of the minimisation + // No file name provided + // prec = truncation precision + public void print(int prec){ + this.prec = prec; + String filename="MinimisationOutput.txt"; + this.print(filename); + } + + // Print the results of the minimisation + // File name provided + // prec = truncation precision + public void print(String filename){ + + if(filename.indexOf('.')==-1)filename = filename+".txt"; + FileOutput fout = new FileOutput(filename, 'n'); + fout.dateAndTimeln(filename); + fout.println(" "); + fout.println("Simplex minimisation, using the method of Nelder and Mead,"); + fout.println("of the function y = f(c[0], c[1], c[2] . . .)"); + this.paraName = new String[this.nParam]; + for(int i=0;i<this.nParam;i++)this.paraName[i]="c["+i+"]"; + + fout.println(); + if(!this.convStatus){ + fout.println("Convergence criterion was not satisfied"); + fout.println("The following results are the current estimates on exiting the minimisation method"); + fout.println(); + } + + fout.println("Value of parameters at the minimum"); + fout.println(" "); + + fout.printtab(" ", this.field); + fout.printtab("Value at", this.field); + fout.printtab("Initial", this.field); + fout.println("Initial"); + + fout.printtab(" ", this.field); + fout.printtab("mimium", this.field); + fout.printtab("estimate", this.field); + fout.println("step"); + + for(int i=0; i<this.nParam; i++){ + fout.printtab(this.paraName[i], this.field); + fout.printtab(Fmath.truncate(paramValue[i],this.prec), this.field); + fout.printtab(Fmath.truncate(this.startH[i],this.prec), this.field); + fout.println(Fmath.truncate(this.step[i],this.prec)); + } + fout.println(); + + fout.println(" "); + + fout.printtab("Number of paramaters"); + fout.println(this.nParam); + fout.printtab("Number of iterations taken"); + fout.println(this.nIter); + fout.printtab("Maximum number of iterations allowed"); + fout.println(this.nMax); + fout.printtab("Number of restarts taken"); + fout.println(this.kRestart); + fout.printtab("Maximum number of restarts allowed"); + fout.println(this.konvge); + fout.printtab("Standard deviation of the simplex at the minimum"); + fout.println(Fmath.truncate(this.simplexSd, this.prec)); + fout.printtab("Convergence tolerance"); + fout.println(this.fTol); + switch(minTest){ + case 0: if(this.convStatus){ + fout.println("simplex sd < the tolerance"); + } + else{ + fout.println("NOTE!!! simplex sd > the tolerance"); + } + break; + } + fout.println(); + fout.println("End of file"); + fout.close(); + } + + // Print the results of the minimisation + // No file name provided + public void print(){ + String filename="MinimisationOutput.txt"; + this.print(filename); + } + + // Get the minimisation status + // true if convergence was achieved + // false if convergence not achieved before maximum number of iterations + // current values then returned + public boolean getConvStatus(){ + return this.convStatus; + } + + // Reset scaling factors (scaleOpt 0 and 1, see below for scaleOpt 2) + public void setScale(int n){ + if(n<0 || n>1)throw new IllegalArgumentException("The argument must be 0 (no scaling) 1(initial estimates all scaled to unity) or the array of scaling factors"); + this.scaleOpt=n; + } + + // Reset scaling factors (scaleOpt 2, see above for scaleOpt 0 and 1) + public void setScale(double[] sc){ + this.scale=sc; + this.scaleOpt=2; + } + + // Get scaling factors + public double[] getScale(){ + return this.scale; + } + + // Reset the minimisation convergence test option + public void setMinTest(int n){ + if(n<0 || n>1)throw new IllegalArgumentException("minTest must be 0 or 1"); + this.minTest=n; + } + + // Get the minimisation convergence test option + public int getMinTest(){ + return this.minTest; + } + + // Get the simplex sd at the minimum + public double getSimplexSd(){ + return this.simplexSd; + } + + // Get the values of the parameters at the minimum + public double[] getParamValues(){ + return this.paramValue; + } + + // Get the function value at minimum + public double getMinimum(){ + return this.minimum; + } + + // Get the number of iterations in Nelder and Mead + public int getNiter(){ + return this.nIter; + } + + + // Set the maximum number of iterations allowed in Nelder and Mead + public void setNmax(int nmax){ + this.nMax = nmax; + } + + // Get the maximum number of iterations allowed in Nelder and Mead + public int getNmax(){ + return this.nMax; + } + + // Get the number of restarts in Nelder and Mead + public int getNrestarts(){ + return this.kRestart; + } + + // Set the maximum number of restarts allowed in Nelder and Mead + public void setNrestartsMax(int nrs){ + this.konvge = nrs; + } + + // Get the maximum number of restarts allowed in Nelder amd Mead + public int getNrestartsMax(){ + return this.konvge; + } + + // Reset the Nelder and Mead reflection coefficient [alpha] + public void setNMreflect(double refl){ + this.rCoeff = refl; + } + + // Get the Nelder and Mead reflection coefficient [alpha] + public double getNMreflect(){ + return this.rCoeff; + } + + // Reset the Nelder and Mead extension coefficient [beta] + public void setNMextend(double ext){ + this.eCoeff = ext; + } + // Get the Nelder and Mead extension coefficient [beta] + public double getNMextend(){ + return this.eCoeff; + } + + // Reset the Nelder and Mead contraction coefficient [gamma] + public void setNMcontract(double con){ + this.cCoeff = con; + } + + // Get the Nelder and Mead contraction coefficient [gamma] + public double getNMcontract(){ + return cCoeff; + } + + // Set the minimisation tolerance + public void setTolerance(double tol){ + this.fTol = tol; + } + + + // Get the minimisation tolerance + public double getTolerance(){ + return this.fTol; + } + +} diff --git a/src/main/java/flanagan/math/MinimisationFunction.java b/src/main/java/flanagan/math/MinimisationFunction.java new file mode 100755 index 0000000000000000000000000000000000000000..d74345975c175faf3e51e43a50a149c30ad75ecb --- /dev/null +++ b/src/main/java/flanagan/math/MinimisationFunction.java @@ -0,0 +1,38 @@ +/* +* Interface MinimisationFunction +* +* This interface provides the abstract method for the function to be +* minimised by the methods in the class, Minimisation +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: April 2003 +* MODIFIED: April 2004 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Minimisation.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2008 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +****************************************************************************************/ + +package flanagan.math; + +// Interface for Minimisation class +// Calculates value of function to be minimised +public interface MinimisationFunction{ + + double function(double[]param); +} \ No newline at end of file diff --git a/src/main/java/flanagan/math/Minimization.java b/src/main/java/flanagan/math/Minimization.java new file mode 100755 index 0000000000000000000000000000000000000000..546de9a2d44d40fcc51299c5ed13686f5bce9785 --- /dev/null +++ b/src/main/java/flanagan/math/Minimization.java @@ -0,0 +1,50 @@ +/* +* Class Minimization +* IDENTICAL TO class Minimisation - created simply to accommodate alternate spelling +* +* Contains methods for finding the values of the +* function parameters that minimize that function +* using the Nelder and Mead Simplex method. +* +* The function needed by the minimization method +* is supplied by though the interface, MinimizationFunction +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: April 2003 +* MODIFIED: 29 December 2005, 18 February 2006, 28 December 2007, 10/12 May 2008 +* +* DOCUMENTATION +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Minimisation.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2008 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.math; + +import java.util.*; +import flanagan.math.Fmath; +import flanagan.io.FileOutput; + +// Minimization/Minimisation class +public class Minimization extends Minimisation{ + + //Constructors + public Minimization(){ + super(); + super.iseOption = false; + } +} diff --git a/src/main/java/flanagan/math/MinimizationFunction.java b/src/main/java/flanagan/math/MinimizationFunction.java new file mode 100755 index 0000000000000000000000000000000000000000..de63303b43a3a01733c40da63cc997235ec03109 --- /dev/null +++ b/src/main/java/flanagan/math/MinimizationFunction.java @@ -0,0 +1,37 @@ +/* +* Interface MinimizationFunction +* +* This interface provides the abstract method for the function to be +* minimised by the methods in the class, Minimization +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: May 2008 to match MinimisationFunction (April 2003) +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Minimisation.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2008 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +****************************************************************************************/ + +package flanagan.math; + +// Interface for Minimization class +// Calculates value of function to be minimised +public interface MinimizationFunction{ + + double function(double[]param); +} \ No newline at end of file diff --git a/src/main/java/flanagan/math/PsRandom.java b/src/main/java/flanagan/math/PsRandom.java new file mode 100755 index 0000000000000000000000000000000000000000..a2bb8f31c3b8ff022db06250da36c5119cd8663e --- /dev/null +++ b/src/main/java/flanagan/math/PsRandom.java @@ -0,0 +1,1906 @@ +/* Program PsRandom +* +* Class for obtaining a single decimal or binary pseudorandom number +* or a sequence of decimal or binary pseudorandom numbers +* Supplements the Java random class with the generation of +* of lorentzian, poissonian, logistic, student's t, pareto, +* exponential, gumbel, weibull, frechet, rayleigh, +* beta distribution, gamma distribution, erlang distribution, +* chi-square distribution, F-distribution, uniform, +* gaussian (normal) and correlated gaussian pseudo-random deviates +* and pseudorandom binary numbers (bits). +* Also offers a choice of Knuth or Park-Miller generation methods. +* +* Binary pseudorandom number calculations are adapted from +* the Numerical Recipes methods written in the C language +* based on the "primitive polynomials modulo 2" method: +* Numerical Recipes in C, The Art of Scientific Computing, +* W.H. Press, S.A. Teukolsky, W.T. Vetterling & B.P. Flannery, +* Cambridge University Press, 2nd Edition (1992) pp 296 - 300. +* (http://www.nr.com/). +* +* AUTHOR: Dr Michael Thomas Flanagan +* DATE: 22 April 2004 +* UPDATE: 21 November 2006, 31 December 2006, 14 April 2007, 19 October 2007, 16-29 March 2008, +* 3 July 2008, 19 September 2008, 28 September 2008, 13 and 18 October 2009 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/PsRandom.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2004 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.math; + +import java.util.*; +import java.io.Serializable; + +import flanagan.analysis.Stat; +import flanagan.roots.*; + +public class PsRandom implements Serializable{ + + private static final long serialVersionUID = 1L; // serial version unique identifier + + private long seed; // current seed value - updated after each generation of a pseudorandom bit + // initial seed supplied as either: + // i. as the current clock time (in milliseconds since 1970) + // (no argument given to the constructor) + // ii. by the user as the constructor argument + // method are available for resetting the value of the seed + + private long initialSeed; // initial seed value + + private int methodOptionDecimal = 1; // Method for calculating pseudorandom decimal numbers + // = 1 Method - Knuth - this class calls the Java Random class which + // implements this method + // See Numerical Recipes in C - W.H. Press et al. (Cambridge) + // 1st edition 1988 p. 212, 2nd edition 1992 p283 for details + // This is the default option used in all methods in this class, + // Pseudorandom, generating a decimal random number, i.e. all but + // the methods to generate pseudorandom binary numbers. + // = 2 Method - Park and Miller random number generator with Bays-Durham shuffle + // after ran1 (Numerical Recipes in C - W.H. Press et al. (Cambridge) + // 2nd edition 1992 p280. + + private Random rr = null; // instance of java.util.Random if Knuth method (default method) used + + private int methodOptionBinary = 1; // Method for calculating pseudorandom binary numbers + // = 1 Method - Primitive polynomials modulo 2 method - version 1 + // This method is the more cumbersome one in terms of coding (see method 2 below) + // but more readily lends itself to a shift register hardware implementation + // = 2 Method - Primitive polynomials modulo 2 method - version 2 + // This method is the more suited to software implementation (compare with method 1 above) + // but lends itself less readily to a shift register hardware implementation + // Method 1 is the default option + + // Park and Miller constants and variables + private long ia = 16807L; + private long im = 2147483647L; + private double am = 1.0D/im; + private long iq = 127773L; + private long ir = 2836L; + private int ntab = 32; + private long ndiv = (1L + (im - 1L)/ntab); + private double eps = 1.2e-7; + private double rnmx = 1.0D - eps; + private long iy = 0L; + private long[] iv = new long[ntab]; + + // Box-Muller variables + private int iset = 0; + private double gset = 0.0D; + + // Polynomial powers of 2 (used in calculation of psedorandom binary numbers) + // See header reference (Numerical Recipes) above for polynomials other than (18, 5, 2, 1, 0) + private long powTwo1 = 1; + private long powTwo2 = 2; + private long powTwo5 = 16; + private long powTwo18 = 131072; + private long mask = powTwo1 + powTwo2 + powTwo5; + + // CONSTRUCTORS + + // Seed taken from the clock + public PsRandom(){ + this.seed = System.currentTimeMillis(); + this.initialSeed = this.seed; + this.rr = new Random(this.seed); + } + + // Seed supplied by user + public PsRandom(long seed){ + this.seed = seed; + this.initialSeed = seed; + this.rr = new Random(this.seed); + } + + // METHODS + + // Resets the value of the seed + public void setSeed(long seed){ + this.seed = seed; + if(this.methodOptionDecimal==1)rr = new Random(this.seed); + } + + // Returns the initial value of the seed + public long getInitialSeed(){ + return this.initialSeed; + } + + // Returns the current value of the seed + public long getSeed(){ + return this.seed; + } + + // Resets the method of calculation of a pseudorandom decimal number + // argument = 1 -> Knuth; argument = 2 -> Parker-Miller + // Default option = 1 + public void setMethodDecimal(int methodOpt){ + if(methodOpt<1 || methodOpt>2)throw new IllegalArgumentException("Argument to PsRandom.setMethodDecimal must 1 or 2\nValue transferred was"+methodOpt); + this.methodOptionDecimal = methodOpt; + if(methodOpt==1)rr = new Random(this.seed); + } + + // Return the binary pseudorandom number method option; 1 = Method 1, 2= Method 2 + public int getMethodDecimal(){ + return this.methodOptionDecimal; + } + // Resets the method of calculation of a pseudorandom binary number + // argument = 1 -> method 1; argument = 2 -> Method 2 + // See above and Numerical Recipes reference (in program header) for method descriptions + // Default option = 1 + public void setMethodBinary(int methodOpt){ + if(methodOpt<1 || methodOpt>2)throw new IllegalArgumentException("Argument to PsRandom.setMethodBinary must 1 or 2\nValue transferred was"+methodOpt); + this.methodOptionBinary = methodOpt; + if(methodOpt==1)rr = new Random(this.seed); + } + + // Return the binary pseudorandom number method option; 1 = Method 1, 2= Method 2 + public int getMethodBinary(){ + return this.methodOptionBinary; + } + + // Returns a pseudorandom double between 0.0 and 1.0 + public double nextDouble(){ + if(this.methodOptionDecimal==1){ + return this.rr.nextDouble(); + } + else{ + return this.parkMiller(); + } + } + + // Returns a pseudorandom double between 0.0 and top + public double nextDouble(double top){ + return top*this.nextDouble(); + } + + // Returns a pseudorandom double between bottom and top + public double nextDouble(double bottom, double top){ + return (top - bottom)*this.nextDouble() + bottom; + } + + // Returns an array, of length arrayLength, of pseudorandom doubles between 0.0 and 1.0 + public double[] doubleArray(int arrayLength){ + double[] array = new double[arrayLength]; + for(int i=0; i<arrayLength; i++){ + array[i] = this.nextDouble(); + } + return array; + } + + // Returns an array, of length arrayLength, of pseudorandom doubles between 0.0 and top + public double[] doubleArray(int arrayLength, double top){ + double[] array = new double[arrayLength]; + for(int i=0; i<arrayLength; i++){ + array[i] = top*this.nextDouble(); + } + return array; + } + + // Returns an array, of length arrayLength, of pseudorandom doubles between bottom and top + public double[] doubleArray(int arrayLength, double bottom, double top){ + double[] array = new double[arrayLength]; + for(int i=0; i<arrayLength; i++){ + array[i] = top*this.nextDouble(); + } + return array; + } + + + // Park and Miller random number generator with Bays-Durham shuffle + // after ran1 Numerical Recipes in C - W.H. Press et al. (Cambridge) + // 2nd edition 1992 p280. + // return a pseudorandom number between 0.0 and 1.0 + public double parkMiller(){ + int jj = 0; + long kk = 0L; + double temp = 0.0D; + this.iy = 0L; + + if(this.seed <= 0L || iy!=0){ + if(-this.seed < 1){ + this.seed = 1; + } + else{ + this.seed = -this.seed; + } + for(int j=ntab+7; j>=0; j--){ + kk = this.seed/iq; + this.seed = ia*( this.seed - kk*iq)- ir*kk; + if(this.seed < 0L) this.seed += im; + if (j < ntab) iv[j] = this.seed; + } + iy = iv[0]; + } + kk = this.seed/iq; + this.seed = ia*(this.seed - kk*iq)-ir*kk; + if(this.seed < 0)this.seed += im; + jj = (int)(iy/ndiv); + iy = iv[jj]; + iv[jj] = this.seed; + if((temp = am*iy) > rnmx){ + return rnmx; + } + else{ + return temp; + } + } + + // Returns a pseudorandom bit + public int nextBit(){ + if(this.methodOptionBinary==1){ + return nextBitM1(); + } + else{ + return nextBitM2(); + } + } + + // Returns an array, of length arrayLength, of pseudorandom bits + public int[] bitArray(int arrayLength){ + int[] bitarray = new int[arrayLength]; + for(int i=0; i<arrayLength; i++){ + bitarray[i]=nextBit(); + } + return bitarray; + } + + // Returns a pseudorandom bit - Method 1 + // This method is the more cumbersome one in terms of coding (see method 2 below) + // but more readily lends itself to a shift register hardware implementation + public int nextBitM1(){ + long newBit; + + newBit = ((this.seed & this.powTwo18) >> 17L) ^ ((this.seed & this.powTwo5) >> 4L) ^ ((this.seed & this.powTwo2) >> 1L) ^ (this.seed & this.powTwo1); + this.seed=(this.seed << 1L) | newBit; + return (int) newBit; + } + + // Returns a pseudorandom bit - Method 2 + // This method is the more suited to software implementation (compare with method 1 above) + // but lends itself less readily to a shift register hardware implementation + public int nextBitM2(){ + int randomBit = 0; + if((this.seed & this.powTwo18)<=0L){ + this.seed = ((this.seed ^ this.mask) << 1L) | this.powTwo1; + randomBit = 1; + } + else{ + this.seed <<= 1L; + randomBit = 0; + } + + return randomBit; + } + + // Returns a Gaussian (normal) random deviate + // mean = the mean, sd = standard deviation + public double nextGaussian(double mean, double sd){ + double ran = 0.0D; + if(this.methodOptionDecimal==1){ + ran=this.rr.nextGaussian(); + } + else{ + ran=this.boxMullerParkMiller(); + } + ran = ran*sd+mean; + return ran; + } + + // Returns a Gaussian (normal) random deviate + // mean = 0.0, sd = 1.0 + public double nextGaussian(){ + double ran = 0.0D; + if(this.methodOptionDecimal==1){ + ran=this.rr.nextGaussian(); + } + else{ + ran=this.boxMullerParkMiller(); + } + return ran; + } + + public double nextNormal(double mean, double sd){ + return nextGaussian(mean, sd); + } + + public double nextNormal(){ + return nextGaussian(); + } + + + // Returns an array of Gaussian (normal) random deviates + // mean = the mean, sd = standard deviation, n = length of array + public double[] gaussianArray(double mean, double sd, int n){ + double[] ran = new double[n]; + for(int i=0; i<n; i++){ + ran[i]=this.nextGaussian(); + } + ran = Stat.standardize(ran); + for(int i=0; i<n; i++){ + ran[i] = ran[i]*sd+mean; + } + return ran; + } + + public double[] normalArray(double mean, double sd, int n){ + return gaussianArray(mean, sd, n); + } + + + // Returns two arrays, both of length n, of correlated Gaussian (normal) random deviates + // of means, mean1 and mean2, and standard deviations, sd1 and sd2, + // and a correlation coefficient, rho + public double[][] correlatedGaussianArrays(double mean1, double mean2, double sd1, double sd2, double rho, int n){ + if(Math.abs(rho)>1.0D)throw new IllegalArgumentException("The correlation coefficient, " + rho + ", must lie between -1 and 1"); + double[][] ran = new double[2][n]; + double[] ran1 = this.gaussianArray(0.0, 1.0, n); + double[] ran2 = this.gaussianArray(0.0, 1.0, n); + + double ranh = 0.0D; + double rhot = Math.sqrt(1.0D - rho*rho); + + for(int i=0; i<n; i++){ + ran[0][i] = ran1[i]*sd1 + mean1; + ran[1][i] = (rho*ran1[i] + rhot*ran2[i])*sd2 + mean2; + } + return ran; + } + + public double[][] correlatedNormalArrays(double mean1, double mean2, double sd1, double sd2, double rho, int n){ + return correlatedGaussianArrays(mean1, mean2, sd1, sd2, rho, n); + } + + + // Box-Muller normal deviate generator + // after gasdev (Numerical Recipes in C - W.H. Press et al. (Cambridge) + // 2nd edition 1992 p289 + // Uses Park and Miller method for generating pseudorandom numbers + double boxMullerParkMiller(){ + double fac = 0.0D, rsq = 0.0D, v1 = 0.0D, v2 = 0.0D; + + if (iset==0){ + do { + v1=2.0*parkMiller()-1.0D; + v2=2.0*parkMiller()-1.0D; + rsq=v1*v1+v2*v2; + }while (rsq >= 1.0D || rsq == 0.0D); + fac=Math.sqrt(-2.0D*Math.log(rsq)/rsq); + gset=v1*fac; + iset=1; + return v2*fac; + }else{ + iset=0; + return gset; + } + } + + + + // returns a two parameter log-normal random deviate + public double nextLogNormal(double mu, double sigma){ + double ran = 0.0D; + + // Create instance of the class holding the two parameter log normal cfd function + LogNormalTwoParFunct logNorm2 = new LogNormalTwoParFunct(); + + // set function variables + logNorm2.mu = mu; + logNorm2.sigma = sigma; + + // required tolerance + double tolerance = 1e-10; + + // lower bound + double lowerBound = 0.0D; + double sigma2 = sigma*sigma; + + // upper bound + double upperBound = 5.0D*Math.sqrt((Math.exp(sigma2) - 1.0D)*Math.exp(2.0D*mu + sigma2)); + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + realR.noLowerBoundExtension(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // Loop to reject failed attempts at calculating the deviate + boolean test=true; + int ii=0; + int imax = 10; // maximum number of successive attempts at calculating deviate allowed + while(test){ + + // set function cfd variable + logNorm2.cfd = this.nextDouble(); + + // call root searching method + ran = realR.falsePosition(logNorm2, lowerBound, upperBound); + + if(!Double.isNaN(ran)){ + test=false; + } + else{ + if(ii>imax){ + System.out.println("class: PsRandom, method: nextLogNormal"); + System.out.println(imax + " successive attempts at calculating a random log-normal deviate failed for values of mu = " + mu + ", sigma = " + sigma); + System.out.println("NaN returned"); + ran = Double.NaN; + test = false; + } + else{ + ii++; + } + } + } + return ran; + } + + public double nextLogNormalTwoPar(double mu, double sigma){ + return nextLogNormal(mu, sigma); + } + + // returns an array of two parameter log-normal pseudo-random deviates + public double[] logNormalArray(double mu, double sigma, int n){ + double[] ran = new double[n]; + + // Create instance of the class holding the two parameter log normal cfd function + LogNormalTwoParFunct logNorm2 = new LogNormalTwoParFunct(); + + // set function variables + logNorm2.mu = mu; + logNorm2.sigma = sigma; + + // required tolerance + double tolerance = 1e-10; + + // lower bound + double lowerBound = 0.0D; + + // upper bound + double sigma2 = sigma*sigma; + double upperBound = 5.0D*Math.sqrt((Math.exp(sigma2) - 1.0D)*Math.exp(2.0D*mu + sigma2)); + + for(int i=0; i<n; i++){ + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + realR.noLowerBoundExtension(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // Loop to reject failed attempts at calculating the deviate + boolean test=true; + int ii=0; + int imax = 10; // maximum number of successive attempts at calculating deviate allowed + while(test){ + + // set function cfd variable + logNorm2.cfd = this.nextDouble(); + + // call root searching method + double rangd = realR.bisect(logNorm2, lowerBound, upperBound); + + if(!Double.isNaN(rangd)){ + test=false; + ran[i] = rangd; + } + else{ + if(ii>imax){ + System.out.println("class: PsRandom, method: logNormalArray"); + System.out.println(imax + " successive attempts at calculating a random gamma deviate failed for values of mu = " + mu + ", sigma = " + sigma); + System.out.println("NaN returned"); + ran[i] = Double.NaN; + test = false; + } + else{ + ii++; + } + } + } + } + return ran; + } + + public double[] logNormalTwoParArray(double mu, double sigma, int n){ + return logNormalArray(mu, sigma, n); + } + + + // returns a three parameter log-normal random deviate + public double nextLogNormalThreePar(double alpha, double beta, double gamma){ + double ran = Double.NaN; + + // Create instance of the class holding the Three Parameter LogNormal cfd function + LogNormalThreeParFunct logNorm3 = new LogNormalThreeParFunct(); + + // set function variables + logNorm3.alpha = alpha; + logNorm3.beta = beta; + logNorm3.gamma = gamma; + + // required tolerance + double tolerance = 1e-10; + + // lower bound + double lowerBound = alpha; + double beta2 = beta*beta; + double upperBound = 5.0D*Math.sqrt((Math.exp(beta2) - 1.0D)*Math.exp(2.0D*Math.log(gamma) + beta2)); + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + realR.noLowerBoundExtension(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // Loop to reject failed attempts at calculating the deviate + boolean test=true; + int ii=0; + int imax = 10; // maximum number of successive attempts at calculating deviate allowed + while(test){ + + // set function cfd variable + logNorm3.cfd = this.nextDouble(); + + // call root searching method + ran = realR.falsePosition(logNorm3, lowerBound, upperBound); + + if(!Double.isNaN(ran)){ + test=false; + } + else{ + if(ii>imax){ + System.out.println("class: PsRandom, method: nextLogNormalThreePar"); + System.out.println(imax + " successive attempts at calculating a random log-normal deviate failed for values of alpha = " + alpha + ", beta = " + beta + ", gamma = " + gamma); + System.out.println("NaN returned"); + ran = Double.NaN; + test = false; + } + else{ + ii++; + } + } + } + return ran; + } + + + // returns an array of three parameter log-normal random deviates + public double[] logNormalThreeParArray(double alpha, double beta, double gamma, int n){ + double[] ran = new double[n]; + + // Create instance of the class holding the Three Parameter log normal cfd function + LogNormalThreeParFunct logNorm3 = new LogNormalThreeParFunct(); + + // set function variables + logNorm3.alpha = alpha; + logNorm3.beta = beta; + logNorm3.gamma = gamma; + + // required tolerance + double tolerance = 1e-10; + + // lower bound + double lowerBound = alpha; + + // upper bound + double beta2 = beta*beta; + double upperBound = 5.0D*Math.sqrt((Math.exp(beta2) - 1.0D)*Math.exp(2.0D*Math.log(gamma) + beta2)); + + for(int i=0; i<n; i++){ + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + realR.noLowerBoundExtension(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // Loop to reject failed attempts at calculating the deviate + boolean test=true; + int ii=0; + int imax = 10; // maximum number of successive attempts at calculating deviate allowed + while(test){ + + // set function cfd variable + logNorm3.cfd = this.nextDouble(); + + // call root searching method, bisectNewtonRaphson + double rangd = realR.falsePosition(logNorm3, lowerBound, upperBound); + + if(!Double.isNaN(rangd)){ + test=false; + ran[i] = rangd; + } + else{ + if(ii>imax){ + System.out.println("class: PsRandom, method: logNormalThreeParArray"); + System.out.println(imax + " successive attempts at calculating a log-normal gamma deviate failed for values of alpha = " + alpha + ", beta = " + beta + ", gamma = " + gamma); + System.out.println("NaN returned"); + ran[i] = Double.NaN; + test = false; + } + else{ + ii++; + } + } + } + } + return ran; + } + + + + // Returns a Lorentzian pseudorandom deviate + // mu = the mean, gamma = half-height widthy + public double nextLorentzian (double mu, double gamma){ + double ran = Math.tan((this.nextDouble()-0.5)*Math.PI); + ran = ran*gamma/2.0D+mu; + + return ran; + } + + + // Returns an array of Lorentzian pseudorandom deviates + // mu = the mean, gamma = half-height width, n = length of array + public double[] lorentzianArray (double mu, double gamma, int n){ + double[] ran = new double[n]; + for(int i=0; i<n; i++){ + ran[i]=Math.tan((this.nextDouble()-0.5)*Math.PI); + ran[i] = ran[i]*gamma/2.0D+mu; + } + return ran; + } + + // Returns a Poissonian pseudorandom deviate + // follows the approach of Numerical Recipes, 2nd Edition, p 294 + public double nextPoissonian(double mean){ + double ran = 0.0D; + double oldm = -1.0D; + double expt = 0.0D; + double em = 0.0D; + double term = 0.0D; + double sq = 0.0D; + double lnMean = 0.0D; + double yDev = 0.0D; + + if(mean < 12.0D){ + if(mean != oldm){ + oldm = mean; + expt = Math.exp(-mean); + } + em = -1.0D; + term = 1.0D; + do{ + ++em; + term *= this.nextDouble(); + }while(term>expt); + ran = em; + } + else{ + if(mean != oldm){ + oldm = mean; + sq = Math.sqrt(2.0D*mean); + lnMean = Math.log(mean); + expt = lnMean - Stat.logGamma(mean+1.0D); + } + do{ + do{ + yDev = Math.tan(Math.PI*this.nextDouble()); + em = sq*yDev+mean; + }while(em<0.0D); + em = Math.floor(em); + term = 0.9D*(1.0D+yDev*yDev)*Math.exp(em*lnMean - Stat.logGamma(em+1.0D)-expt); + }while(this.nextDouble()>term); + ran = em; + } + return ran; + } + + // Returns an array of Poisson random deviates + // follows the approach of Numerical Recipes, 2nd Edition, p 294 + public double[] poissonianArray(double mean, int n){ + double[] ran = new double[n]; + double oldm = -1.0D; + double expt = 0.0D; + double em = 0.0D; + double term = 0.0D; + double sq = 0.0D; + double lnMean = 0.0D; + double yDev = 0.0D; + + if(mean < 12.0D){ + for(int i=0; i<n; i++){ + if(mean != oldm){ + oldm = mean; + expt = Math.exp(-mean); + } + em = -1.0D; + term = 1.0D; + do{ + ++em; + term *= this.nextDouble(); + }while(term>expt); + ran[i] = em; + } + } + else{ + for(int i=0; i<n; i++){ + if(mean != oldm){ + oldm = mean; + sq = Math.sqrt(2.0D*mean); + lnMean = Math.log(mean); + expt = lnMean - Stat.logGamma(mean+1.0D); + } + do{ + do{ + yDev = Math.tan(Math.PI*this.nextDouble()); + em = sq*yDev+mean; + }while(em<0.0D); + em = Math.floor(em); + term = 0.9D*(1.0D+yDev*yDev)*Math.exp(em*lnMean - Stat.logGamma(em+1.0D)-expt); + }while(this.nextDouble()>term); + ran[i] = em; + } + } + return ran; + } + + // Returns a Binomial pseudorandom deviate from a binomial + // distribution of nTrial trials each of probablity, prob, + // after bndlev Numerical Recipes in C - W.H. Press et al. (Cambridge) + // 2nd edition 1992 p295. + public double nextBinomial(double prob, int nTrials){ + + if(prob<0.0D || prob>1.0D)throw new IllegalArgumentException("The probablity provided, " + prob + ", must lie between 0 and 1)"); + + double binomialDeviate = 0.0D; // the binomial deviate to be returned + double deviateMean = 0.0D; // mean of deviate to be produced + double testDeviate = 0.0D; // test deviate + double workingProb = 0.0; // working value of the probability + double logProb = 0.0; // working value of the probability + double probOld = -1.0D; // previous value of the working probability + double probC = -1.0D; // complementary value of the working probability + double logProbC = -1.0D; // log of the complementary value of the working probability + int nOld= -1; // previous value of trials counter + double enTrials = 0.0D; // (double) trials counter + double oldGamma = 0.0D; // a previous log Gamma function value + double tanW = 0.0D; // a working tangent + double hold0 = 0.0D; // a working holding variable + int jj; // counter + + workingProb=(prob <= 0.5D ? prob : 1.0-prob); // distribution invariant on swapping prob for 1 - prob + deviateMean = nTrials*workingProb; + + if(nTrials < 25) { + // if number of trials greater than 25 use direct method + binomialDeviate=0.0D; + for (jj=1;jj<=nTrials;jj++)if (this.nextDouble() < workingProb) ++binomialDeviate; + } + else if(deviateMean < 1.0D) { + // if fewer than 1 out of 25 events - Poisson approximation is accurate + double expOfMean=Math.exp(-deviateMean); + testDeviate=1.0D; + for(jj=0;jj<=nTrials;jj++) { + testDeviate *= this.nextDouble(); + if (testDeviate < expOfMean) break; + } + binomialDeviate=(jj <= nTrials ? jj : nTrials); + + } + else{ + // use rejection method + if(nTrials != nOld) { + // if nTrials has changed compute useful quantities + enTrials = (double)nTrials; + oldGamma = Stat.logGamma(enTrials + 1.0D); + nOld = nTrials; + } + if(workingProb != probOld) { + // if workingProb has changed compute useful quantities + probC = 1.0 - workingProb; + logProb = Math.log(workingProb); + logProbC = Math.log(probC); + probOld = workingProb; + } + + double sq = Math.sqrt(2.0*deviateMean*probC); + do{ + do{ + double angle = Math.PI*this.nextDouble(); + tanW = Math.tan(angle); + hold0 = sq*tanW + deviateMean; + }while(hold0 < 0.0D || hold0 >= (enTrials + 1.0D)); //rejection test + hold0 = Math.floor(hold0); // integer value distribution + testDeviate = 1.2D*sq*(1.0D + tanW*tanW)*Math.exp(oldGamma - Stat.logGamma(hold0 + 1.0D) - Stat.logGamma(enTrials - hold0 + 1.0D) + hold0*logProb + (enTrials - hold0)*logProbC); + }while(this.nextDouble() > testDeviate); // rejection test + binomialDeviate=hold0; + } + + if(workingProb != prob) binomialDeviate = nTrials - binomialDeviate; // symmetry transformation + + return binomialDeviate; + } + + // Returns an array of n Binomial pseudorandom deviates from a binomial + // distribution of nTrial trials each of probablity, prob, + // after bndlev Numerical Recipes in C - W.H. Press et al. (Cambridge) + // 2nd edition 1992 p295. + public double[] binomialArray(double prob, int nTrials, int n){ + + if(nTrials<n)throw new IllegalArgumentException("Number of deviates requested, " + n + ", must be less than the number of trials, " + nTrials); + if(prob<0.0D || prob>1.0D)throw new IllegalArgumentException("The probablity provided, " + prob + ", must lie between 0 and 1)"); + + double[] ran = new double[n]; // array of deviates to be returned + + double binomialDeviate = 0.0D; // the binomial deviate to be returned + double deviateMean = 0.0D; // mean of deviate to be produced + double testDeviate = 0.0D; // test deviate + double workingProb = 0.0; // working value of the probability + double logProb = 0.0; // working value of the probability + double probOld = -1.0D; // previous value of the working probability + double probC = -1.0D; // complementary value of the working probability + double logProbC = -1.0D; // log of the complementary value of the working probability + int nOld= -1; // previous value of trials counter + double enTrials = 0.0D; // (double) trials counter + double oldGamma = 0.0D; // a previous log Gamma function value + double tanW = 0.0D; // a working tangent + double hold0 = 0.0D; // a working holding variable + int jj; // counter + + double probOriginalValue = prob; + for(int i=0; i<n; i++){ + prob = probOriginalValue; + workingProb=(prob <= 0.5D ? prob : 1.0-prob); // distribution invariant on swapping prob for 1 - prob + deviateMean = nTrials*workingProb; + + if(nTrials < 25) { + // if number of trials greater than 25 use direct method + binomialDeviate=0.0D; + for(jj=1;jj<=nTrials;jj++)if (this.nextDouble() < workingProb) ++binomialDeviate; + } + else if(deviateMean < 1.0D) { + // if fewer than 1 out of 25 events - Poisson approximation is accurate + double expOfMean=Math.exp(-deviateMean); + testDeviate=1.0D; + for (jj=0;jj<=nTrials;jj++) { + testDeviate *= this.nextDouble(); + if (testDeviate < expOfMean) break; + } + binomialDeviate=(jj <= nTrials ? jj : nTrials); + + } + else{ + // use rejection method + if(nTrials != nOld) { + // if nTrials has changed compute useful quantities + enTrials = (double)nTrials; + oldGamma = Stat.logGamma(enTrials + 1.0D); + nOld = nTrials; + } + if(workingProb != probOld) { + // if workingProb has changed compute useful quantities + probC = 1.0 - workingProb; + logProb = Math.log(workingProb); + logProbC = Math.log(probC); + probOld = workingProb; + } + + double sq = Math.sqrt(2.0*deviateMean*probC); + do{ + do{ + double angle = Math.PI*this.nextDouble(); + tanW = Math.tan(angle); + hold0 = sq*tanW + deviateMean; + }while(hold0 < 0.0D || hold0 >= (enTrials + 1.0D)); //rejection test + hold0 = Math.floor(hold0); // integer value distribution + testDeviate = 1.2D*sq*(1.0D + tanW*tanW)*Math.exp(oldGamma - Stat.logGamma(hold0 + 1.0D) - Stat.logGamma(enTrials - hold0 + 1.0D) + hold0*logProb + (enTrials - hold0)*logProbC); + }while(this.nextDouble() > testDeviate); // rejection test + binomialDeviate=hold0; + } + + if(workingProb != prob) binomialDeviate = nTrials - binomialDeviate; // symmetry transformation + + ran[i] = binomialDeviate; + } + + return ran; + } + + + // Returns a Pareto pseudorandom deviate + public double nextPareto(double alpha, double beta){ + return Math.pow(1.0D-this.nextDouble(), -1.0D/alpha)*beta; + } + + // Returns an array, of Pareto pseudorandom deviates, of length n + public double[] paretoArray (double alpha, double beta, int n){ + double[] ran = new double[n]; + for(int i=0; i<n; i++){ + ran[i] = Math.pow(1.0D-this.nextDouble(), -1.0D/alpha)*beta; + } + return ran; + } + + // Returns an exponential pseudorandom deviate + public double nextExponential(double mu, double sigma){ + return mu - Math.log(1.0D-this.nextDouble())*sigma; + } + + // Returns an array, of exponential pseudorandom deviates, of length n + public double[] exponentialArray (double mu, double sigma, int n){ + double[] ran = new double[n]; + for(int i=0; i<n; i++){ + ran[i] = mu - Math.log(1.0D-this.nextDouble())*sigma; + } + return ran; + } + + // Returns a Rayleigh pseudorandom deviate + public double nextRayleigh(double sigma){ + return Math.sqrt(-2.0D*Math.log(1.0D-this.nextDouble()))*sigma; + } + + // Returns an array, of Rayleigh pseudorandom deviates, of length n + public double[] rayleighArray (double sigma, int n){ + double[] ran = new double[n]; + for(int i=0; i<n; i++){ + ran[i] = Math.sqrt(-2.0D*Math.log(1.0D-this.nextDouble()))*sigma; + } + return ran; + } + + // Returns a minimal Gumbel (Type I EVD) random deviate + // mu = location parameter, sigma = scale parameter + public double nextMinimalGumbel(double mu, double sigma){ + return Math.log(Math.log(1.0D/(1.0D-this.nextDouble())))*sigma+mu; + } + + // Returns an array of minimal Gumbel (Type I EVD) random deviates + // mu = location parameter, sigma = scale parameter, n = length of array + public double[] minimalGumbelArray(double mu, double sigma, int n){ + double[] ran = new double[n]; + for(int i=0; i<n; i++){ + ran[i] = Math.log(Math.log(1.0D/(1.0D-this.nextDouble())))*sigma+mu; + } + return ran; + } + + // Returns a maximal Gumbel (Type I EVD) random deviate + // mu = location parameter, sigma = scale parameter + public double nextMaximalGumbel(double mu, double sigma){ + return mu-Math.log(Math.log(1.0D/(1.0D-this.nextDouble())))*sigma; + } + + // Returns an array of maximal Gumbel (Type I EVD) random deviates + // mu = location parameter, sigma = scale parameter, n = length of array + public double[] maximalGumbelArray(double mu, double sigma, int n){ + double[] ran = new double[n]; + for(int i=0; i<n; i++){ + ran[i] = mu-Math.log(Math.log(1.0D/(1.0D-this.nextDouble())))*sigma; + } + return ran; + } + + // Returns a Frechet (Type II EVD) random deviate + // mu = location parameter, sigma = scale parameter, gamma = shape parameter + public double nextFrechet(double mu, double sigma, double gamma){ + return Math.pow((1.0D/(Math.log(1.0D/this.nextDouble()))),1.0D/gamma)*sigma + mu; + } + + // Returns an array of Frechet (Type II EVD) random deviates + // mu = location parameter, sigma = scale parameter, gamma = shape parameter, n = length of array + public double[] frechetArray(double mu, double sigma, double gamma, int n){ + double[] ran = new double[n]; + for(int i=0; i<n; i++){ + ran[i] = Math.pow((1.0D/(Math.log(1.0D/this.nextDouble()))),1.0D/gamma)*sigma + mu; + } + return ran; + } + + // Returns a Weibull (Type III EVD) random deviate + // mu = location parameter, sigma = scale parameter, gamma = shape parameter + public double nextWeibull(double mu, double sigma, double gamma){ + return Math.pow(-Math.log(1.0D-this.nextDouble()),1.0D/gamma)*sigma + mu; + } + + // Returns an array of Weibull (Type III EVD) random deviates + // mu = location parameter, sigma = scale parameter, gamma = shape parameter, n = length of array + public double[] weibullArray(double mu, double sigma, double gamma, int n){ + double[] ran = new double[n]; + for(int i=0; i<n; i++){ + ran[i] = Math.pow(-Math.log(1.0D-this.nextDouble()),1.0D/gamma)*sigma + mu; + } + return ran; + } + + // Returns an array of Logistic distribution random deviates + // mu = location parameter, scale = scale parameter + public double nextLogistic(double mu, double scale){ + return 2.0D*scale*Fmath.atanh(2.0D*this.nextDouble() - 1.0D) + mu; + } + + // Returns an array of Logistic distribution random deviate + // mu = location parameter, scale = scale parameter, n is the length of the returned array + public double[] logisticArray(double mu, double scale, int n){ + double[] ran = new double[n]; + for(int i=0; i<n; i++) ran[i] = 2.0D*scale*Fmath.atanh(2.0D*this.nextDouble() - 1.0D) + mu; + return ran; + } + + + // Returns a Student t random deviate + // nu = the degrees of freedom + public double nextStudentT(int nu){ + + double ran = 0.0D; + + // Create instance of the class holding the Student's t cfd function + StudentTfunct strt = new StudentTfunct(); + + // change set function variables + strt.nu = nu; + + // Set initial range for search + double centre = 0.0D; + double range = 100.0D; + if(nu>2)range = nu/(nu-2); + + // lower bound + double lowerBound = centre - 5.0D*range; + + // upper bound + double upperBound = centre + 5.0D*range; + + // required tolerance + double tolerance = 1e-10; + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // Loop to reject failed attempts at calculating the deviate + boolean test=true; + int ii=0; + int imax = 10; // maximum number of successive attempts at calculating deviate allowed + while(test){ + + // set function cfd varaible + strt.cfd = this.nextDouble(); + + // call root searching method + ran = realR.falsePosition(strt, lowerBound, upperBound); + + if(!Double.isNaN(ran)){ + test=false; + } + else{ + if(ii>imax){ + System.out.println("class: PsRandom, method: studentT"); + System.out.println(imax + " successive attempts at calculating a random Student's T deviate failed for values of nu = " + nu); + System.out.println("NaN returned"); + ran = Double.NaN; + test = false; + } + else{ + ii++; + } + } + } + return ran; + + } + + // Returns an array of Student's t random deviates + // nu = the degrees of freedom + public double[] studentTarray(int nu, int n){ + + double[] ran = new double[n]; + + // Create instance of the class holding the Student's t cfd function + StudentTfunct strt = new StudentTfunct(); + + // set function variables + strt.nu = nu; + + // Set initial range for search + double centre = 0.0D; + double range = 100.0D; + if(nu>2)range = nu/(nu-2); + + // required tolerance + double tolerance = 1e-10; + + // lower bound + double lowerBound = centre - 5.0D*range; + + // upper bound + double upperBound = centre + 5.0D*range; + + for(int i=0; i<n; i++){ + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // Loop to reject failed attempts at calculating the deviate + boolean test=true; + int ii=0; + int imax = 10; // maximum number of successive attempts at calculating deviate allowed + while(test){ + + // set function cfd variable + strt.cfd = this.nextDouble(); + + // call root searching method, bisectNewtonRaphson + double rangd = realR.falsePosition(strt, lowerBound, upperBound); + + if(!Double.isNaN(rangd)){ + test=false; + ran[i] = rangd; + } + else{ + if(ii>imax){ + System.out.println("class: PsRandom, method: studentTarray"); + System.out.println(imax + " successive attempts at calculating a random gamma deviate failed for values of nu = " + nu); + System.out.println("NaN returned"); + ran[i] = Double.NaN; + test = false; + } + else{ + ii++; + } + } + } + } + return ran; + } + + // method for generating a Beta random deviate + public double nextBeta(double alpha, double beta){ + return nextBeta(0.0D, 1.0D, alpha, beta); + } + + + // method for generating a Beta random deviate + public double nextBeta(double min, double max, double alpha, double beta){ + + double ran = 0.0D; + + // Create instance of the class holding the Beta cfd function + BetaFunct bart = new BetaFunct(); + + // set function variables + bart.alpha = alpha; + bart.beta = beta; + bart.min = min; + bart.max = max; + + // required tolerance + double tolerance = 1e-10; + + // lower bound + double lowerBound = min; + // upper bound + double upperBound = max; + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + realR.noLowerBoundExtension(); + realR.noUpperBoundExtension(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // Loop to reject failed attempts at calculating the deviate + boolean test=true; + int ii=0; + int imax = 10; // maximum number of successive attempts at calculating deviate allowed + while(test){ + + // set function cfd variable + bart.cfd = this.nextDouble(); + + // call root searching method, false position + ran = realR.falsePosition(bart, lowerBound, upperBound); + + if(!Double.isNaN(ran)){ + test=false; + } + else{ + if(ii>imax){ + System.out.println("class: PsRandom, method: nextBeta"); + System.out.println(imax + " successive attempts at calculating a random beta deviate failed for values of min = " + min + ", max = " + max + ", alpha = " + alpha + ", beta = " + beta); + System.out.println("NaN returned"); + ran = Double.NaN; + test = false; + } + else{ + ii++; + } + } + } + + return ran; + + } + + // method for generating an array of Beta random deviates + public double[] betaArray(double alpha, double beta, int n){ + return betaArray(0.0D, 1.0D, alpha, beta, n); + } + + // method for generating an array of Beta random deviates + public double[] betaArray(double min, double max, double alpha, double beta, int n){ + + double[] ran = new double[n]; + + // Create instance of the class holding the Beta cfd function + BetaFunct bart = new BetaFunct(); + + // set function variables + bart.alpha = alpha; + bart.beta = beta; + bart.min = min; + bart.max = max; + + // required tolerance + double tolerance = 1e-10; + + // lower bound + double lowerBound = min; + + // upper bound + double upperBound = max; + + for(int i=0; i<n; i++){ + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + realR.noLowerBoundExtension(); + realR.noUpperBoundExtension(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // Loop to reject failed attempts at calculating the deviate + boolean test=true; + int ii=0; + int imax = 10; // maximum number of successive attempts at calculating deviate allowed + while(test){ + + // set function cfd variable + bart.cfd = this.nextDouble(); + + // call root searching method + double rangd = realR.bisect(bart, lowerBound, upperBound); + + if(!Double.isNaN(rangd)){ + test=false; + ran[i] = rangd; + } + else{ + if(ii>imax){ + System.out.println("class: PsRandom, method: betaArray"); + System.out.println(imax + " successive attempts at calculating a random beta deviate failed for values of min = " + min + ", max = " + max + ", alpha = " + alpha + ", beta = " + beta); + System.out.println("NaN returned"); + ran[i] = Double.NaN; + test = false; + } + else{ + ii++; + } + } + } + } + + return ran; + } + + + // method for generating a Gamma random deviate + public double nextGamma(double mu, double beta, double gamma){ + + double ran = 0.0D; // variable to hold the random deviate + + // Create instance of the class holding the Gamma cfd function + GammaFunct gart = new GammaFunct(); + + // set function variables + gart.mu = mu; + gart.beta = beta; + gart.gamma = gamma; + + // Set initial range for search + double range = Math.sqrt(gamma)*beta; + + // required tolerance + double tolerance = 1e-10; + + // lower bound + double lowerBound = mu; + + // upper bound + double upperBound = mu + 5.0D*range; + if(upperBound<=lowerBound)upperBound += range; + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + realR.noLowerBoundExtension(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // Loop to reject failed attempts at calculating the deviate + boolean test=true; + int ii=0; + int imax = 10; // maximum number of successive attempts at calculating deviate allowed + while(test){ + + // set function cfd variable + gart.cfd = this.nextDouble(); + + // call root searching method, bisect + ran = realR.bisect(gart, lowerBound, upperBound); + + if(!Double.isNaN(ran)){ + test=false; + } + else{ + if(ii>imax){ + System.out.println("class: PsRandom, method: nextGamma"); + System.out.println(imax + " successive attempts at calculating a random gamma deviate failed for values of mu = " + mu + ", beta = " + beta + ", gamma = " + gamma); + System.out.println("NaN returned"); + ran = Double.NaN; + test = false; + } + else{ + ii++; + } + } + } + + return ran; + + } + + // method for generating an array of Gamma random deviates + public double[] gammaArray(double mu, double beta, double gamma, int n){ + + double[] ran = new double[n]; + + // Create instance of the class holding the gamma cfd function + GammaFunct gart = new GammaFunct(); + + // set function variables + gart.mu = mu; + gart.beta = beta; + gart.gamma = gamma; + + // Set initial range for search + double range = Math.sqrt(gamma)*beta; + + // required tolerance + double tolerance = 1e-10; + + // lower bound + double lowerBound = mu; + + // upper bound + double upperBound = mu + 5.0D*range; + if(upperBound<=lowerBound)upperBound += range; + + for(int i=0; i<n; i++){ + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + realR.noLowerBoundExtension(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // Loop to reject failed attempts at calculating the deviate + boolean test=true; + int ii=0; + int imax = 10; // maximum number of successive attempts at calculating deviate allowed + while(test){ + + // set function cfd variable + gart.cfd = this.nextDouble(); + + // call root searching method, bisectNewtonRaphson + double rangd = realR.bisect(gart, lowerBound, upperBound); + + if(!Double.isNaN(rangd)){ + test=false; + ran[i] = rangd; + } + else{ + if(ii>imax){ + System.out.println("class: PsRandom, method: gammaArray"); + System.out.println(imax + " successive attempts at calculating a random gamma deviate failed for values of mu = " + mu + ", beta = " + beta + ", gamma = " + gamma); + System.out.println("NaN returned"); + ran[i] = Double.NaN; + test = false; + } + else{ + ii++; + } + } + } + } + + return ran; + + } + + // method for generating an Erlang random deviate + public double nextErlang(double lambda, int kay){ + return nextGamma(0.0D, 1.0D/lambda, (double) kay); + } + + + // method for generating an array of Erlang random deviates + public double[] erlangArray(double lambda, int kay, int n){ + return gammaArray(0.0D, 1.0D/lambda, (double) kay, n); + } + + // CHI-SQUARE + // method for generating an array of Chi-Square random deviates + public double[] chiSquareArray(int nu, int n){ + if(nu<=0)throw new IllegalArgumentException("The degrees of freedom [nu], " + nu + ", must be greater than zero"); + + double[] ran = new double[n]; + + // Create instance of the class holding the chiSquare cfd function + ChiSquareFunct csrt = new ChiSquareFunct(); + + // set function variables + csrt.nu = nu; + + // required tolerance + double tolerance = 1e-10; + + // lower bound + double lowerBound = 0.0D; + + // upper bound + double upperBound = 5.0D*Math.sqrt(2*nu); + + for(int i=0; i<n; i++){ + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + realR.noLowerBoundExtension(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // Loop to reject failed attempts at calculating the deviate + boolean test=true; + int ii=0; + int imax = 10; // maximum number of successive attempts at calculating deviate allowed + while(test){ + + // set function cfd variable + csrt.cfd = this.nextDouble(); + + // call root searching method + double rangd = realR.falsePosition(csrt, lowerBound, upperBound); + + if(!Double.isNaN(rangd)){ + test=false; + ran[i] = rangd; + } + else{ + if(ii>imax){ + System.out.println("class: PsRandom, method: chiSquareArray"); + System.out.println(imax + " successive attempts at calculating a random chi square deviate failed for values of nu = " + nu); + System.out.println("NaN returned"); + ran[i] = Double.NaN; + test = false; + } + else{ + ii++; + } + } + } + } + return ran; + } + + // method for generating a Chi-Square random deviate + public double nextChiSquare(int nu){ + if(nu<=0)throw new IllegalArgumentException("The degrees of freedom [nu], " + nu + ", must be greater than zero"); + + double ran = 0.0D; + + // Create instance of the class holding the chiSquare cfd function + ChiSquareFunct csrt = new ChiSquareFunct(); + + // set function variables + csrt.nu = nu; + + // required tolerance + double tolerance = 1e-10; + + // lower bound + double lowerBound = 0.0D; + // upper bound + double upperBound = 5.0D*Math.sqrt(2*nu); + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + realR.noLowerBoundExtension(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // Loop to reject failed attempts at calculating the deviate + boolean test=true; + int ii=0; + int imax = 10; // maximum number of successive attempts at calculating deviate allowed + while(test){ + + // set function cfd variable + csrt.cfd = this.nextDouble(); + + // call root searching method + ran = realR.falsePosition(csrt, lowerBound, upperBound); + + if(!Double.isNaN(ran)){ + test=false; + } + else{ + if(ii>imax){ + System.out.println("class: PsRandom, method: nextChiSqauare"); + System.out.println(imax + " successive attempts at calculating a random Chi Square deviate failed for values of nu = " + nu); + System.out.println("NaN returned"); + ran = Double.NaN; + test = false; + } + else{ + ii++; + } + } + } + return ran; + } + + // F-DISTRIBUTION + // method for generating an F-distribution random deviate + public double nextF(int nu1, int nu2){ + double ran = Double.NaN; + + // Create instance of the class holding the F-distribution cfd function + Ffunct frt = new Ffunct(); + + // set function variables + frt.nu1 = nu1; + frt.nu2 = nu2; + // required tolerance + double tolerance = 1e-10; + + // lower bound + double lowerBound = 0.0D; + + // upper bound + double upperBound = 10.0D; + if(nu2>4)upperBound = 5.0D*Math.sqrt(2*nu2*nu2*(nu1+nu2-2)/(nu1*(nu2-2)*(nu2-2)*(nu2-4))); + + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + realR.noLowerBoundExtension(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // Loop to reject failed attempts at calculating the deviate + boolean test=true; + int ii=0; + int imax = 10; // maximum number of successive attempts at calculating deviate allowed + while(test){ + + // set function cfd variable + frt.cfd = this.nextDouble(); + + // call root searching method + ran = realR.falsePosition(frt, lowerBound, upperBound); + + if(!Double.isNaN(ran)){ + test=false; + } + else{ + if(ii>imax){ + System.out.println("class: PsRandom, method: nextF"); + System.out.println(imax + " successive attempts at calculating a random F-distribution deviate failed for values of nu1 = " + nu1 + ", nu2 = " + nu2); + System.out.println("NaN returned"); + ran = Double.NaN; + test = false; + } + else{ + ii++; + } + } + } + return ran; + } + + + // method for generating an array of F-distribution random deviates + public double[] fArray(int nu1, int nu2, int n){ + double[] ran = new double[n]; + + // Create instance of the class holding the F-distribution cfd function + Ffunct frt = new Ffunct(); + + // set function variables + frt.nu1 = nu1; + frt.nu2 = nu2; + + // required tolerance + double tolerance = 1e-10; + + // lower bound + double lowerBound = 0.0D; + + // upper bound + double upperBound = 10.0D; + double nu1d = (double) nu1; + double nu2d = (double) nu2; + if(nu2>4)upperBound = 5.0D*Math.sqrt(2*nu2d*nu2d*(nu1d+nu2d-2)/(nu1d*(nu2d-2)*(nu2d-2)*(nu2d-4))); + + for(int i=0; i<n; i++){ + + // Create instance of RealRoot + RealRoot realR = new RealRoot(); + + // Set extension limits + realR.noLowerBoundExtension(); + + // Set tolerance + realR.setTolerance(tolerance); + + // Supress error messages and arrange for NaN to be returned as root if root not found + realR.resetNaNexceptionToTrue(); + realR.supressLimitReachedMessage(); + realR.supressNaNmessage(); + + // Loop to reject failed attempts at calculating the deviate + boolean test=true; + int ii=0; + int imax = 10; // maximum number of successive attempts at calculating deviate allowed + while(test){ + + // set function cfd variable + frt.cfd = this.nextDouble(); + + // call root searching method + double rangd = realR.falsePosition(frt, lowerBound, upperBound); + if(!Double.isNaN(rangd)){ + test=false; + ran[i] = rangd; + } + else{ + if(ii>imax){ + System.out.println("class: PsRandom, method: fArray"); + System.out.println(imax + " successive attempts at calculating a random f-distribution deviate failed for values of nu1 = " + nu1 + ", nu2 = " + nu2); + System.out.println("NaN returned"); + ran[i] = Double.NaN; + test = false; + } + else{ + ii++; + } + } + } + } + return ran; + } + + // PSEUDORANDOM INTEGERS + // Returns a pseudorandom integer between 0.0 and top + public int nextInteger(int top){ + double pr0 = this.nextDouble(); + int pr1 = (int)Math.round(pr0*top); + return pr1; + } + + // Returns a pseudorandom integer between bottom and top + public int nextInteger(int bottom, int top){ + double pr0 = this.nextDouble(); + int pr1 = (int)Math.round(pr0*(top - bottom)); + return pr1 + bottom; + } + + // Returns an array, of length arraylength, of pseudorandom integers between 0.0 and top + public int[] integerArray(int arrayLength, int top){ + int[] array = new int[arrayLength]; + for(int i=0; i<arrayLength; i++){ + array[i] = this.nextInteger(top); + } + return array; + } + + // Returns an array, of length arraylength, of pseudorandom integers between bottom and top + public int[] integerArray(int arrayLength, int bottom, int top){ + int[] array = new int[arrayLength]; + for(int i=0; i<arrayLength; i++){ + array[i] = this.nextInteger(bottom - top) + bottom; + } + return array; + } + + // Returns an array, of length top+1, of unique pseudorandom integers between bottom and top + // i.e. no integer is repeated and all integers between bottom and top inclusive are present + public int[] uniqueIntegerArray(int bottom, int top){ + int range = top - bottom; + int[] array = uniqueIntegerArray(range); + for(int i=0; i<range+1; i++)array[i] += bottom; + return array; + } + + + // Returns an array, of length top+1, of unique pseudorandom integers between 0 and top + // i.e. no integer is repeated and all integers between 0 and top inclusive are present + public int[] uniqueIntegerArray(int top){ + int numberOfIntegers = top + 1; // number of unique pseudorandom integers returned + int[] array = new int[numberOfIntegers]; // array to contain returned unique pseudorandom integers + boolean allFound = false; // will equal true when all required integers found + int nFound = 0; // number of required pseudorandom integers found + boolean[] found = new boolean[numberOfIntegers]; // = true when integer corresponding to its index is found + for(int i=0; i<numberOfIntegers; i++)found[i] = false; + + boolean test0 = true; + while(test0){ + int ii = this.nextInteger(top); + if(!found[ii]){ + array[nFound] = ii; + found[ii] = true; + nFound++; + if(nFound==numberOfIntegers)test0 = false; + } + } + return array; + } + + // Return the serial version unique identifier + public static long getSerialVersionUID(){ + return PsRandom.serialVersionUID; + } +} diff --git a/src/main/java/flanagan/math/StudentTfunct.java b/src/main/java/flanagan/math/StudentTfunct.java new file mode 100644 index 0000000000000000000000000000000000000000..1762588a8590856c5e21d4c3fc1d10b2f59a9675 --- /dev/null +++ b/src/main/java/flanagan/math/StudentTfunct.java @@ -0,0 +1,17 @@ +package flanagan.math; + +import flanagan.analysis.Stat; +import flanagan.roots.RealRootFunction; + +// Class to evaluate the Student's t-function +public class StudentTfunct implements RealRootFunction { + public int nu = 0; + public double cfd = 0.0D; + + public double function(double x){ + + double y = cfd - Stat.studentTcdf(x, nu); + + return y; + } +} diff --git a/src/main/java/flanagan/math/TimeAndDate.java b/src/main/java/flanagan/math/TimeAndDate.java new file mode 100755 index 0000000000000000000000000000000000000000..3d39ddb1c42f0ee2c0751759db7af223bb2bb1e2 --- /dev/null +++ b/src/main/java/flanagan/math/TimeAndDate.java @@ -0,0 +1,2113 @@ +/* +* Class TimeAndDate +* +* USAGE: Methods concerned with returning times dates and timing events +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 28 September 2009 +* AMENDED: 2-3 October 2009 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web pages: +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* http://www.ee.ucl.ac.uk/~mflanaga/java/TimeAndDate.html +* +* Copyright (c) 2009 +* +* PERMISSION TO COPY: +* +* Redistributions of this source code, or parts of, must retain the above +* copyright notice, this list of conditions and the following disclaimer. +* +* Redistribution in binary form of all or parts of this class, must reproduce +* the above copyright, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the distribution. +* +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all +* copies and associated documentation or publications. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.math; + +import java.util.Calendar; + +public class TimeAndDate{ + + private Calendar cal = Calendar.getInstance(); // instance of abstract class Calendar + private String dayOfTheWeek = null; // day of the week + private int dayOfTheMonth = 0; // day of the month + private String monthOfTheYear = null; // month of the year + private int monthAsInteger = 0; // month as integer + private int year = 0; // year + private String fullDate = null; // date as 'day name', 'day of month' 'month name' year + private String date = null; // 'day of month' 'month name' 'year' + private String shortDateUK = null; // UK Format - 'day of month'.'month'.'year final two digits' + private String shortDateUS = null; // US Format - 'month'/'day of month'/'year final two digits' + + private String[] days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; + private String[] months = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; + private int[] monthDays = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + private int hour24 = -1; // hour of the day (24 hour clock) + private String hour12 = null; // hour of the day as am or pm (12 hour clock) + private int minute = -1; // minute of the hour + private int second = -1; // seconds of the minute + private int millisecond = -1; // milliseconds of the second + private String shortTime24 = null; // time as hour.minute (24 hour clock) + private String shortTime12 = null; // time as hour.minute AM or PM (12 hour clock) + private String midTime24 = null; // time as hour.minute.second (24 hour clock) + private String midTime12 = null; // time as hour.minute.second AM or PM (12 hour clock) + private String fullTime24 = null; // time as hour.minute.second.millisecond (24 hour clock) + private String fullTime12 = null; // time as hour.minute.second.millisecond AM OR PM (12 hour clock) + + private long tStart = 0L; // start time + private boolean startCheck = false; // = true when timing start set + private long tEnd = 0L; // end time + private boolean endCheck = false; // = true when timing end set + private long totalTime = 0L; // tEnd - tStart + + private String changeDate = null; // next BST change + private boolean backForw = true; // = true next BST change is back, i.e if date is within BST; = false next BST change = forward + + private int easterMonth = 0; // Easter Sunday month + private int easterDay = 0; // Easter Sunday day of the month + private String easterDayName = null; // Easter Sunday day name, i.e. "Sunday" - calculated as a check of the method + + private int yearHold = 0; // Last calculated year + private int monthHold = 0; // Last calculated month + private int dayHold = 0; // Last calculated day of the month + private String dayNameHold = null; // Last calculated day name + + + // CONSTRUCTOR + public TimeAndDate(){ + + } + + // Causes the program to wait for nSeconds seconds before continuing (int) + public void waitFor(int nSeconds){ + long t0,t1; + t0=System.currentTimeMillis(); + do{ + t1=System.currentTimeMillis(); + } + while ((t1-t0)<nSeconds*1000); + } + + // Causes the program to wait for nSeconds seconds before continuing (long) + public void waitFor(long nSeconds){ + if(nSeconds>Long.MAX_VALUE/1000){ + System.out.println("Class: TimeAndDate, method: wait(long nSeconds), nSeconds is too large for this method - the value has been replaced by " + Long.MAX_VALUE/1000); + nSeconds = Long.MAX_VALUE/1000; + } + long t0,t1; + t0=System.currentTimeMillis(); + do{ + t1=System.currentTimeMillis(); + } + while ((t1-t0)<nSeconds*1000); + } + + // Causes the program to wait for nSeconds seconds before continuing (double) + public void waitFor(double nSeconds){ + long tt = 0L; + if(nSeconds>Math.pow(2.0, 63)-1.0){ + System.out.println("Class: TimeAndDate, method: wait(double nSeconds), nSeconds is too large for this method - the value has been replaced by " + Long.MAX_VALUE/1000); + tt = Long.MAX_VALUE; + } + else{ + tt = Conv.convert_double_to_long(nSeconds*1000); + } + long t0,t1; + t0=System.currentTimeMillis(); + do{ + t1=System.currentTimeMillis(); + } + while ((t1-t0)<tt); + } + + // Marker method for starting the timing of a bloc of code + public void blocStart(){ + this.tStart = System.currentTimeMillis(); + this.startCheck = true; + } + + // Marker method for ending the timing of a bloc of code and for returning the total time + public long blocEnd(){ + if(this.startCheck){ + this.tEnd = System.currentTimeMillis(); + this.totalTime = this.tEnd - this.tStart; + this.endCheck = true; + } + else{ + throw new IllegalArgumentException("No start marker has been set"); + } + return this.totalTime; + } + + // Returns total time taken to run a bloc of code + public long blocTime(){ + if(this.endCheck){ + return this.totalTime; + } + else{ + if(!this.startCheck){ + System.out.println("Class Time: method totalTime: No start marker has been set - -9999 rturned"); + return -9999L; + } + else{ + System.out.println("Class Time: method totalTime: No end marker has been set - -8888 rturned"); + return -8888L; + } + } + } + + // Get the hour of the day (24 hour clock) + public int getHour24(){ + this.hour24 = cal.get(Calendar.HOUR_OF_DAY); + return this.hour24; + } + + // Get the hour of the day, am or pm (12 hour clock) + public String getHour12(){ + int hour = cal.get(Calendar.HOUR); + int amPm = cal.get(Calendar.AM_PM); + if(amPm==0){ + this.hour12 = (new Integer(hour)).toString() + " AM"; + } + else{ + this.hour12 = (new Integer(hour)).toString() + " PM"; + } + return this.hour12; + } + + // Get the minute of the hour + public int getMinute(){ + this.minute = cal.get(Calendar.MINUTE); + return this.minute; + } + + // Get the second of the minute + public int getSecond(){ + this.second = cal.get(Calendar.SECOND); + return this.second; + } + + // Get the millisecond of the second + public int getMilliSecond(){ + this.millisecond = cal.get(Calendar.MILLISECOND); + return this.millisecond; + } + + // Get time as hour.minute (24 hour clock) + public String getShortTime24(){ + int hourI = this.getHour24(); + this.shortTime24 = (new Integer(hourI)).toString(); + int minI = this.getMinute(); + if(minI<10){ + this.shortTime24 += ".0" + minI; + } + else{ + this.shortTime24 += "." + minI; + } + return this.shortTime24; + } + + // Get time as hour.minute AM or PM (12 hour clock) + public String getShortTime12(){ + int hourI = cal.get(Calendar.HOUR); + int amPm = cal.get(Calendar.AM_PM); + this.shortTime12 = (new Integer(hourI)).toString(); + int minI = this.getMinute(); + if(minI<10){ + this.shortTime12 += ".0" + minI; + } + else{ + this.shortTime12 += "." + minI; + } + if(amPm==0){ + this.shortTime12 += " " + "AM"; + } + else{ + this.shortTime12 += " " + "PM"; + } + return this.shortTime12; + } + + // Get time as hour.minute.second (24 hour clock) + public String getMidTime24(){ + int hourI = this.getHour24(); + this.midTime24 = (new Integer(hourI)).toString(); + int minI = this.getMinute(); + if(minI<10){ + this.midTime24 += ".0" + minI; + } + else{ + this.midTime24 += "." + minI; + } + int secI = this.getSecond(); + if(secI<10){ + this.midTime24 += ".0" + secI; + } + else{ + this.midTime24 += "." + secI; + } + return this.midTime24; + } + + // Get time as hour.minute.second AM or PM (12 hour clock) + public String getMidTime12(){ + int hourI = cal.get(Calendar.HOUR); + int amPm = cal.get(Calendar.AM_PM); + this.midTime12 = (new Integer(hourI)).toString(); + int minI = this.getMinute(); + if(minI<10){ + this.midTime12 += ".0" + minI; + } + else{ + this.midTime12 += "." + minI; + } + int secI = this.getSecond(); + if(secI<10){ + this.midTime12 += ".0" + secI; + } + else{ + this.midTime12 += "." + secI; + } + if(amPm==0){ + this.midTime12 += " " + "AM"; + } + else{ + this.midTime12 += " " + "PM"; + } + return this.midTime12; + } + + // Get time as hour.minute.second.millisecond (24 hour clock) + public String getFullTime24(){ + int hourI = this.getHour24(); + this.fullTime24 = (new Integer(hourI)).toString(); + int minI = this.getMinute(); + if(minI<10){ + this.fullTime24 += ".0" + minI; + } + else{ + this.fullTime24 += "." + minI; + } + int secI = this.getSecond(); + if(secI<10){ + this.fullTime24 += ".0" + secI; + } + else{ + this.fullTime24 += "." + secI; + } + int msecI = this.getMilliSecond(); + if(msecI<10){ + this.fullTime24 += ".00" + msecI; + } + else{ + if(msecI<100){ + this.fullTime24 += ".0" + msecI; + } + else{ + this.fullTime24 += "." + msecI; + } + } + return this.fullTime24; + } + + // Get time as hour.minute.second.millisecond AM OR PM (12 hour clock) + public String getFullTime12(){ + int hourI = cal.get(Calendar.HOUR); + int amPm = cal.get(Calendar.AM_PM); + this.fullTime12 = (new Integer(hourI)).toString(); + int minI = this.getMinute(); + if(minI<10){ + this.fullTime12 += ".0" + minI; + } + else{ + this.fullTime12 += "." + minI; + } + int secI = this.getSecond(); + if(secI<10){ + this.fullTime12 += ".0" + secI; + } + else{ + this.fullTime12 += "." + secI; + } + int msecI = this.getMilliSecond(); + if(msecI<10){ + this.fullTime12 += ".00" + msecI; + } + else{ + if(msecI<100){ + this.fullTime12 += ".0" + msecI; + } + else{ + this.fullTime12 += "." + msecI; + } + } + if(amPm==0){ + this.fullTime12 += " " + "AM"; + } + else{ + this.fullTime12 += " " + "PM"; + } + return this.fullTime12; + } + + // Return the current computer time in milliseconds + public long getComputerTime(){ + return System.currentTimeMillis(); + } + + // Converts a date to milliseconds since 0 hours 0 minutes 0 seconds on 1 Jan 1970 + public long dateToJavaMilliSecondsUK(int year, int month, int dayOfTheMonth, String dayOfTheWeek, int hour, int min, int sec, int millisec){ + + long ms = 0L; // milliseconds since 0 hours 0 minutes 0 seconds and o milliseconds on 1 Jan 1970 + + // Day of the week as integer + int dayIndicator = this.getDayOfTheWeekAsInteger(dayOfTheWeek); + + // British Summer Time adjustment + long bst = 0; + this.backForw = checkBST(dayOfTheWeek, dayOfTheMonth, hour, month, dayIndicator); + if(this.backForw)bst = 1; + + // millisecond calculation + if(year>=1970){ + // Date after the zero computer time + long yearDiff = 0L; + int yearTest = year-1; + while(yearTest>=1970){ + yearDiff += 365; + if(this.leapYear(yearTest))yearDiff++; + yearTest--; + } + yearDiff *= 24L*60L*60L*1000L; + + long monthDiff = 0L; + int monthTest = month - 1; + while(monthTest>0){ + monthDiff += monthDays[monthTest-1]; + if(this.leapYear(year) && monthTest==2)monthDiff++; + monthTest--; + } + monthDiff *= 24L*60L*60L*1000L; + + long dayDiff = (dayOfTheMonth - 1)*24L*60L*60L*1000L; + + ms = yearDiff + monthDiff + dayDiff + (hour - bst)*60L*60L*1000L + min*60L*1000L + sec*1000L + millisec; + } + else{ + // Date before the zero computer time + long yearDiff = 0L; + int yearTest = year + 1; + while(yearTest<1970){ + yearDiff += 365; + if(this.leapYear(yearTest))yearDiff++; + yearTest++; + } + yearDiff *= 24L*60L*60L*1000L; + + long monthDiff = 0L; + int monthTest = month - 1; + while(monthTest>0){ + monthDiff += monthDays[monthTest-1]; + if(this.leapYear(year) && monthTest==2)monthDiff++; + monthTest--; + } + + monthDiff *= 24L*60L*60L*1000L; + + long dayDiff = (dayOfTheMonth - 1)*24L*60L*60L*1000L; + + monthDiff = monthDiff + dayDiff + (hour - bst)*60L*60L*1000L + min*60L*1000L + sec*1000L + millisec; + + long myear = 365L; + if(this.leapYear(year))myear++; + myear *= 24L*60L*60L*1000L; + + ms = myear - monthDiff; + ms += yearDiff; + ms = -ms; + } + + return ms; + } + + // Check whether within British summer time period + public boolean checkBST(){ + + String dayOfTheWeek = this.getDayOfTheWeek(); + int dayOfTheMonth = this.getDayOfTheMonth(); + int hour = this.getMonthAsInteger(); + int month = this.getMonthAsInteger(); + int dayIndicator = this.getDayOfTheWeekAsInteger(dayOfTheWeek); + + return this.checkBST(dayOfTheWeek, dayOfTheMonth, hour, month, dayIndicator); + } + + // Check whether within British summer time period - private method for internal use + private boolean checkBST(String dayOfTheWeek, int dayOfTheMonth, int hour, int month, int dayIndicator){ + + if(month>3 && month<10){ + this.backForw = true; + } + else{ + if(month==3 && dayOfTheMonth>24){ + if(dayIndicator==0){ + if(hour>=1)this.backForw = true; + } + else{ + if(dayIndicator>0 && dayIndicator<dayOfTheMonth-24)this.backForw = true; + } + } + else{ + if(month==10 && dayOfTheMonth>24){ + if(dayIndicator==0){ + if(hour<=2)this.backForw = true; + } + else{ + this.backForw = true; + if(dayIndicator>0 && dayIndicator<dayOfTheMonth-24)this.backForw = false; + } + } + } + } + + return this.backForw; + } + + // Returns the day of the week as an integer (Sunday = 1, Monday = 1 etc) + public int getDayOfTheWeekAsInteger(){ + + String dayOfTheWeek = this.getDayOfTheWeek(); + + return this.getDayOfTheWeekAsInteger(dayOfTheWeek) + 1; + } + + // Returns the day of the week as an integer (Sunday = 0, Monday = 1 etc) - private method for internal use + private int getDayOfTheWeekAsInteger(String dayOfTheWeek){ + + + // Day of the week as integer + int counter = 0; + int dayIndicator = 0; + boolean test = true; + while(test){ + if(dayOfTheWeek.equals(days[counter])){ + dayIndicator = counter; + test = false; + } + else{ + counter++; + if(counter>6)throw new IllegalArgumentException(dayOfTheWeek + " is not recognised as a day of the week"); + } + } + + return dayIndicator; + } + + // Calculates the next British Summer Time clock change for the current date + public String nextBstClockChange(){ + + this.backForw = true; // = true change back, i.e if date is within bst; = false change = forward + + String dayOfTheWeek = this.getDayOfTheWeek(); + int dayOfTheMonth = this.getDayOfTheMonth(); + int hour = this.getMonthAsInteger(); + int month = this.getMonthAsInteger(); + + // Day of the week as integer + int dayIndicator = this.getDayOfTheWeekAsInteger(dayOfTheWeek); + + // Check whether within British summer time period + this.backForw = checkBST(dayOfTheWeek, dayOfTheMonth, hour, month, dayIndicator); + + // Find next Sunday to today's date + int daysDiff = 0; + int newDayOfTheMonth = dayOfTheMonth; + int newMonth = month; + int newYear = year; + int oldNewDayOfTheMonth = newDayOfTheMonth; + int oldMonth = newMonth; + int oldYear = newYear; + if(dayIndicator!=0)daysDiff = 7-dayIndicator; + newDayOfTheMonth = dayOfTheMonth + daysDiff; + int monthD = monthDays[newMonth-1]; + if(newMonth==2 && this.leapYear(newYear))monthD++; + if(newDayOfTheMonth>monthD){ + newDayOfTheMonth -= monthD; + newMonth++; + if(newMonth==13){ + newMonth = 1; + newYear = oldYear + 1; + } + } + + if(!backForw){ + boolean test = true; + while(test){ + if(newMonth==3 && newDayOfTheMonth>24){ + this.changeDate = "Sunday, " + newDayOfTheMonth + " March " + year + ", one hour forward"; + test = false; + } + else{ + newDayOfTheMonth += 7; + monthD = monthDays[newMonth-1]; + if(newMonth==2 && this.leapYear(newYear))monthD++; + if(newDayOfTheMonth>monthD){ + newDayOfTheMonth -= monthD; + newMonth++; + if(newMonth==13){ + newMonth = 1; + newYear = newYear + 1; + } + } + } + } + } + else{ + boolean test = true; + while(test){ + if(newMonth==10 && newDayOfTheMonth>24){ + this.changeDate = "Sunday, " + newDayOfTheMonth + " October " + year + ", one hour back"; + test = false; + } + else{ + newDayOfTheMonth += 7; + monthD = monthDays[newMonth-1]; + if(newMonth==2 && this.leapYear(newYear))monthD++; + if(newDayOfTheMonth>monthD){ + newDayOfTheMonth -= monthD; + newMonth++; + if(newMonth==13){ + newMonth = 1; + newYear = newYear + 1; + } + } + } + } + } + return this.changeDate; + } + + + // Returns the the day of the week by name, e.g. Sunday + public String getDayOfTheWeek(){ + int dayAsInt = cal.get(Calendar.DAY_OF_WEEK); + this.dayOfTheWeek = this.days[dayAsInt - 1]; + return this.dayOfTheWeek; + } + + // Returns the the day of the month as integer, e.g. 24 for the 24th day of the month + public int getDayOfTheMonth(){ + this.dayOfTheMonth = cal.get(Calendar.DAY_OF_MONTH); + return this.dayOfTheMonth; + } + + // Returns the the month by name, e.g. January + public String getMonth(){ + int monthAsInt = cal.get(Calendar.MONTH); + this.monthOfTheYear = this.months[monthAsInt]; + return this.monthOfTheYear; + } + + // Returns the month as an integer, e.g. January as 1 + public int getMonthAsInteger(){ + this.monthAsInteger = cal.get(Calendar.MONTH) + 1; + return this.monthAsInteger; + } + + // Returns the month as an integer, e.g. January as 1, private method for internal use + public int getMonthAsInteger(String month){ + int monthI = 0; + boolean test = true; + int counter = 0; + while(test){ + if(month.equals(this.months[counter])){ + monthI = counter + 1; + test = false; + } + else{ + counter++; + if(counter==12)throw new IllegalArgumentException(month + " is not recognised as a valid month name"); + } + } + return monthI; + } + + // Returns the year as four digit number + public int getYear(){ + this.year = cal.get(Calendar.YEAR); + return this.year; + } + + // Returns the date as 'day of month' 'month name' 'year' + public String getDate(){ + this.date = (new Integer(this.getDayOfTheMonth())).toString(); + this.date += " " + this.getMonth(); + this.date += " " + this.getYear(); + return this.date; + } + + // Returns the date as 'day name', 'day of month' 'month name' year + public String getFullDate(){ + this.fullDate = this.getDayOfTheWeek(); + this.fullDate += ", " + this.getDayOfTheMonth(); + this.fullDate += " " + this.getMonth(); + this.fullDate += " " + this.getYear(); + return this.fullDate; + } + + // Returns the date as the UK short format - 'day of month'.'month number'.'year final two digits' + public String getShortDateUK(){ + this.shortDateUK = (new Integer(this.getDayOfTheMonth())).toString(); + if(this.shortDateUK.length()<2)this.shortDateUK = "0" + this.shortDateUK; + int monthI = this.getMonthAsInteger(); + if(monthI<10){ + this.shortDateUK += ".0" + monthI; + } + else{ + this.shortDateUK += "." + monthI; + } + String yearS = (new Integer(this.getYear())).toString(); + this.shortDateUK += "." + yearS.substring(2); + return this.shortDateUK; + } + + // Returns the date as the US short format - 'month number'/'day of month'/'year final two digits' + public String getShortDateUS(){ + this.shortDateUS = (new Integer(this.getMonthAsInteger())).toString(); + if(this.shortDateUS.length()<2)this.shortDateUS = "0" + this.shortDateUS; + int dayI = this.getDayOfTheMonth(); + if(dayI<10){ + this.shortDateUS += "/0" + dayI; + } + else{ + this.shortDateUS += "/" + dayI; + } + String yearS = (new Integer(this.getYear())).toString(); + this.shortDateUS+= "/" + yearS.substring(2); + return this.shortDateUS; + } + + // Returns true if entered date (xxxT) is later than the current date (xxx) otherwise returns false, private method for internal use + private boolean direction(int dayOfTheMonthT, int monthT, int yearT, int dayOfTheMonth, int month, int year){ + boolean test = true; + boolean direction = false; + if(year>yearT){ + direction = true; + } + else{ + if(year<yearT){ + direction = false; + } + else{ + if(month>monthT){ + direction = true; + } + else{ + if(month<monthT){ + direction = false; + } + else{ + if(dayOfTheMonth>=dayOfTheMonthT){ + direction = true; + } + else{ + direction = false; + } + } + } + } + } + return direction; + } + + // Returns the day of the week for a given date - month as String, e.g. January + public String getDayOfDate(int dayOfTheMonth, String month, int year){ + int monthI = this.getMonthAsInteger(month); + return getDayOfDate(dayOfTheMonth, monthI, year); + } + + + // Returns the day of the week for a given date - month as integer, January = 1 + public String getDayOfDate(int dayOfTheMonth, int month, int year){ + + String dayOfDate = null; + int yearT = this.getYear(); + int monthT = this.getMonthAsInteger(); + int dayOfTheMonthT = this.getDayOfTheMonth(); + int dayI = this.getDayOfTheWeekAsInteger(); + int febOrRest = 0; + + + boolean direction = direction(dayOfTheMonthT, monthT, yearT, dayOfTheMonth, month, year); + + if(direction){ + boolean test = true; + while(test){ + if(yearT==year && monthT==month && dayOfTheMonthT==dayOfTheMonth){ + dayOfDate = days[dayI-1]; + test = false; + } + else{ + dayOfTheMonthT++; + febOrRest = this.monthDays[monthT-1]; + if(this.leapYear(yearT) && monthT==2)febOrRest++; + if(dayOfTheMonthT>febOrRest){ + dayOfTheMonthT -= febOrRest; + monthT++; + } + if(monthT==13){ + monthT = 1; + yearT++; + } + dayI++; + if(dayI==8)dayI=1; + } + } + } + else{ + boolean test = true; + while(test){ + if(yearT==year && monthT==month && dayOfTheMonthT==dayOfTheMonth){ + dayOfDate = days[dayI-1]; + test = false; + } + else{ + dayOfTheMonthT--; + int monthIndex = monthT - 2; + if(monthIndex<0)monthIndex = 11; + febOrRest = this.monthDays[monthIndex]; + if(this.leapYear(yearT) && monthT==3)febOrRest++; + if(dayOfTheMonthT==0){ + dayOfTheMonthT = febOrRest; + monthT--; + } + if(monthT==0){ + monthT = 12; + yearT--; + } + dayI--; + if(dayI==0)dayI=7; + } + } + } + + + return dayOfDate; + } + + // Returns date of next Easter Sunday (1700 - 2299) + // Western Church - Gregorian calendar + // Uses the 'BBC algorithm' (http://www.bbc.co.uk/dna/h2g2/A653267) - checked only between 1700 and 2299 + public String easterSunday(){ + int year = this.getYear(); + if(year>2299)System.out.println(year + " is outside the range for which this algorithm has been checked, 1700 - 2299"); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + + int rem1 = year%19; + int quo1 = year/100; + int rem2 = year%100; + int quo2 = quo1/4; + int rem3 = quo1%4; + int quo3 = rem2/4; + int rem4 = rem2%4; + + int quo4 = (quo1 + 8)/25; + int quo5 = (quo1 - quo4 + 1)/3; + int rem5 = (19*rem1 + quo1 - quo2 - quo5 + 15)%30; + int rem6 = (32 + 2*rem3 + 2*quo3 - rem5 - rem4)%7; + int quo6 = (rem1 + 11*rem5 + 22*rem6)/451; + int sum1 = rem5 + rem6 - 7*quo6 + 114; + + this.easterMonth = sum1/31; + this.easterDay = (sum1%31) + 1; + + boolean direction = this.direction(day, month, year, this.easterDay, this.easterMonth, year); + if(direction){ + this.dayHold = this.easterDay; + this.monthHold = this.easterMonth; + this.yearHold = year; + this.dayNameHold = "Sunday"; + this.easterDayName = this.getDayOfDate(this.easterDay, this.easterMonth, year); + return this.easterDayName + ", " + this.easterDay + " " + months[this.easterMonth-1] + " " + year; + } + else{ + return easterSunday(++year); + } + } + + // Returns date of the Easter Sunday (1700 - 2299) + // Western Church - Gregorian calendar + // Uses the 'BBC algorithm' (http://www.bbc.co.uk/dna/h2g2/A653267) - checked only between 1700 and 2299 + public String easterSunday(int year){ + if(year<1700 || year>2299)System.out.println(year + " is outside the range for which this algorithm has been checked, 1700 - 2299"); + + int rem1 = year%19; + int quo1 = year/100; + int rem2 = year%100; + int quo2 = quo1/4; + int rem3 = quo1%4; + int quo3 = rem2/4; + int rem4 = rem2%4; + + int quo4 = (quo1 + 8)/25; + int quo5 = (quo1 - quo4 + 1)/3; + int rem5 = (19*rem1 + quo1 - quo2 - quo5 + 15)%30; + int rem6 = (32 + 2*rem3 + 2*quo3 - rem5 - rem4)%7; + int quo6 = (rem1 + 11*rem5 + 22*rem6)/451; + int sum1 = rem5 + rem6 - 7*quo6 + 114; + + this.easterMonth = sum1/31; + this.easterDay = (sum1%31) + 1; + this.dayHold = this.easterDay; + this.monthHold = this.easterMonth; + this.yearHold = year; + this.dayNameHold = "Sunday"; + + this.easterDayName = this.getDayOfDate(this.easterDay, this.easterMonth, year); + + return this.easterDayName + ", " + this.easterDay + " " + months[this.easterMonth-1] + " " + year; + + } + + // Returns date of next Good Friday + // See easterDay() for limitations of the method + public String goodFriday(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.easterSunday(year); + int monthGF = this.easterMonth; + int dayGF = this.easterDay - 2; + if(dayGF<1){ + int dayCheck = monthDays[monthGF-2]; + if(this.leapYear(year) && monthGF==3)dayCheck++; + dayGF = dayCheck + dayGF; + monthGF--; + } + boolean direction = this.direction(day, month, year, dayGF, monthGF, year); + if(!direction)year++; + return goodFriday(year); + } + + // Returns date of Good Friday for the entered year + // See easterDay() for limitations of the method + public String goodFriday(int year){ + this.easterSunday(year); + int monthGF = this.easterMonth; + int dayGF = this.easterDay - 2; + if(dayGF<1){ + int dayCheck = monthDays[monthGF-2]; + if(this.leapYear(year) && monthGF==3)dayCheck++; + dayGF = dayCheck + dayGF; + monthGF--; + } + this.dayHold = dayGF; + this.monthHold = monthGF; + this.yearHold = year; + this.dayNameHold = "Friday"; + return "Friday, " + dayGF + " " + months[monthGF-1] + " " + year; + } + + // Returns date of next Maundy Thursday + // See easterDay() for limitations of the method + public String maundyThursday(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.maundyThursday(year); + int monthMT = this.monthHold; + int dayMT = this.dayHold; + boolean direction = this.direction(day, month, year, dayMT, monthMT, year); + if(!direction)year++; + return maundyThursday(year); + } + + // Returns date of Maundy Thursday for the entered year + // See easterDay() for limitations of the method + public String maundyThursday(int year){ + this.goodFriday(year); + int monthMT = this.monthHold; + int dayMT = this.dayHold - 1; + if(dayMT<1){ + int dayCheck = monthDays[monthMT-2]; + if(this.leapYear(year) && monthMT==3)dayCheck++; + dayMT = dayCheck + dayMT; + monthMT--; + } + this.dayHold = dayMT; + this.monthHold = monthMT; + this.yearHold = year; + this.dayNameHold = "Friday"; + return "Thursday, " + dayMT + " " + months[monthMT-1] + " " + year; + } + + // Returns date of next Ash Wednesday + // See easterDay() for limitations of the method + public String ashWednesday(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.ashWednesday(year); + int monthAW = this.monthHold; + int dayAW = this.dayHold; + boolean direction = this.direction(day, month, year, dayAW, monthAW, year); + if(!direction)year++; + return ashWednesday(year); + } + + // Returns date of Ash Wednesday for the entered year + // See easterDay() for limitations of the method + public String ashWednesday(int year){ + this.easterSunday(year); + int monthAW = this.easterMonth; + int dayAW = this.easterDay; + int counter = 1; + while(counter<=40){ + dayAW --; + if(dayAW<1){ + int dayCheck = monthDays[monthAW-2]; + if(this.leapYear(year) && monthAW==3)dayCheck++; + dayAW = dayCheck + dayAW; + monthAW--; + } + if(this.getDayOfDate(dayAW, monthAW, year).equals("Sunday")){ + // Sunday - day does not counts + } + else{ + // Not a Sunday - day counts + counter++; + } + } + this.dayHold = dayAW; + this.monthHold = monthAW; + this.yearHold = year; + this.dayNameHold = "Wednesday"; + + return "Wednesday, " + dayAW + " " + months[monthAW-1] + " " + year; + } + + // Returns date of next Shrove Tuesday + // See easterDay() for limitations of the method + public String shroveTuesday(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.shroveTuesday(year); + int monthST = this.monthHold; + int dayST = this.dayHold; + boolean direction = this.direction(day, month, year, dayST, monthST, year); + if(!direction)year++; + return shroveTuesday(year); + } + + // Returns date of Shrove Tuesday for the entered year + // See easterDay() for limitations of the method + public String shroveTuesday(int year){ + this.ashWednesday(year); + int monthST = this.monthHold; + int dayST = this.dayHold - 1; + if(dayST<1){ + int dayCheck = monthDays[monthST-2]; + if(this.leapYear(year) && monthST==3)dayCheck++; + dayST = dayCheck + dayST; + monthST--; + } + this.dayHold = dayST; + this.monthHold = monthST; + this.yearHold = year; + this.dayNameHold = "Tuesday"; + + return "Tuesday, " + dayST + " " + months[monthST-1] + " " + year; + } + + // Returns date of next Palm Sunday + // See easterDay() for limitations of the method + public String palmSunday(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.palmSunday(year); + int monthPS = this.monthHold; + int dayPS = this.dayHold; + boolean direction = this.direction(day, month, year, dayPS, monthPS, year); + if(!direction)year++; + return palmSunday(year); + } + + // Returns date of Palm Sunday for the entered year + // See easterDay() for limitations of the method + public String palmSunday(int year){ + this.easterSunday(year); + int monthPS = this.easterMonth; + int dayPS = this.easterDay - 7; + if(dayPS<1){ + int dayCheck = monthDays[monthPS-2]; + if(this.leapYear(year) && monthPS==3)dayCheck++; + dayPS = dayCheck + dayPS; + monthPS--; + } + this.dayHold = dayPS; + this.monthHold = monthPS; + this.yearHold = year; + this.dayNameHold = "Sunday"; + + return "Sunday, " + dayPS + " " + months[monthPS-1] + " " + year; + } + + // Returns date of next Advent Sunday + // See easterDay() for limitations of the method + public String adventSunday(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.adventSunday(year); + int monthPS = this.monthHold; + int dayPS = this.dayHold; + boolean direction = this.direction(day, month, year, dayPS, monthPS, year); + if(!direction)year++; + return adventSunday(year); + } + + // Returns date of Advent Sunday for the entered year + // See easterDay() for limitations of the method + public String adventSunday(int year){ + this.saintAndrewsDay(year); + int monthAS = this.monthHold; + int dayAS = this.dayHold; + String dayNameAS = this.dayNameHold; + int dayASI = this.getDayOfTheWeekAsInteger(dayNameAS); + if(dayASI<4){ + dayAS -= dayASI; + if(dayAS<1){ + int dayCheck = monthDays[monthAS-2]; + if(this.leapYear(year) && monthAS==3)dayCheck++; + dayAS = dayCheck + dayAS; + monthAS--; + } + } + else{ + dayAS += (7 - dayASI); + int dayCheck = monthDays[monthAS-1]; + if(this.leapYear(year) && monthAS==2)dayCheck++; + if(dayAS>dayCheck){ + dayAS = dayAS - dayCheck; + monthAS++; + } + } + + this.dayHold = dayAS; + this.monthHold = monthAS; + this.yearHold = year; + this.dayNameHold = "Sunday"; + + return "Sunday, " + dayAS + " " + months[monthAS-1] + " " + year; + } + + + // Returns date of next Trinity Sunday + // See easterDay() for limitations of the method + public String trinitySunday(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.trinitySunday(year); + int monthTS = this.monthHold; + int dayTS = this.dayHold; + boolean direction = this.direction(day, month, year, dayTS, monthTS, year); + if(!direction)year++; + return trinitySunday(year); + } + + // Returns date of Trinity Sunday for the entered year + // See easterDay() for limitations of the method + public String trinitySunday(int year){ + this.whitSunday(year); + int monthTS = this.monthHold; + int dayTS = this.dayHold + 7; + int dayCheck = monthDays[monthTS-1]; + if(this.leapYear(year) && monthTS==2)dayCheck++; + if(dayTS>dayCheck){ + dayTS = dayTS - dayCheck; + monthTS++; + } + this.dayHold = dayTS; + this.monthHold = monthTS; + this.yearHold = year; + this.dayNameHold = "Sunday"; + + return "Sunday, " + dayTS + " " + months[monthTS-1] + " " + year; + } + + // Returns date of next Corpus Christi + // See easterDay() for limitations of the method + public String corpusChristi(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.corpusChristi(year); + int monthTS = this.monthHold; + int dayTS = this.dayHold; + boolean direction = this.direction(day, month, year, dayTS, monthTS, year); + if(!direction)year++; + return corpusChristi(year); + } + + // Returns date of Corpus Christi for the entered year + // See easterDay() for limitations of the method + public String corpusChristi(int year){ + this.trinitySunday(year); + int monthTS = this.monthHold; + int dayTS = this.dayHold + 4; + int dayCheck = monthDays[monthTS-1]; + if(this.leapYear(year) && monthTS==2)dayCheck++; + if(dayTS>dayCheck){ + dayTS = dayTS - dayCheck; + monthTS++; + } + this.dayHold = dayTS; + this.monthHold = monthTS; + this.yearHold = year; + this.dayNameHold = "Thursday"; + + return "Thursday, " + dayTS + " " + months[monthTS-1] + " " + year; + } + + // Returns date of next Sunday after Corpus Christi + // See easterDay() for limitations of the method + public String sundayAfterCorpusChristi(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.sundayAfterCorpusChristi(year); + int monthTS = this.monthHold; + int dayTS = this.dayHold; + boolean direction = this.direction(day, month, year, dayTS, monthTS, year); + if(!direction)year++; + return sundayAfterCorpusChristi(year); + } + + // Returns date of Sunday after Corpus Christi for the entered year + // See easterDay() for limitations of the method + public String sundayAfterCorpusChristi(int year){ + this.corpusChristi(year); + int monthTS = this.monthHold; + int dayTS = this.dayHold + 3; + int dayCheck = monthDays[monthTS-1]; + if(this.leapYear(year) && monthTS==2)dayCheck++; + if(dayTS>dayCheck){ + dayTS = dayTS - dayCheck; + monthTS++; + } + this.dayHold = dayTS; + this.monthHold = monthTS; + this.yearHold = year; + this.dayNameHold = "Sunday"; + + return "Sunday, " + dayTS + " " + months[monthTS-1] + " " + year; + } + + // Returns date of next Ascension Thursday + // See easterDay() for limitations of the method + public String ascensionThursday(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.ascensionThursday(year); + int monthAT = this.monthHold; + int dayAT = this.dayHold; + boolean direction = this.direction(day, month, year, dayAT, monthAT, year); + if(!direction)year++; + return ascensionThursday(year); + } + + // Returns date of Ascension Thursday for the entered year + // See easterDay() for limitations of the method + public String ascensionThursday(int year){ + this.easterSunday(year); + int monthAT = this.easterMonth; + int dayAT = this.easterDay + 39; + int dayCheck1 = monthDays[monthAT-1]; + if(this.leapYear(year) && monthAT==2)dayCheck1++; + int dayCheck2 = monthDays[monthAT]; + if(this.leapYear(year) && monthAT==1)dayCheck2++; + if(dayAT>(dayCheck1 + dayCheck2)){ + dayAT = dayAT - (dayCheck1 + dayCheck2); + monthAT += 2; + } + else{ + if(dayAT>dayCheck1){ + dayAT = dayAT - dayCheck1; + monthAT += 1; + } + } + + this.dayHold = dayAT; + this.monthHold = monthAT; + this.yearHold = year; + this.dayNameHold = "Thursday"; + + return "Thursday, " + dayAT + " " + months[monthAT-1] + " " + year; + } + + // Returns date of next Sunday after Ascension Thursday + // See easterDay() for limitations of the method + public String sundayAfterAscension(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.sundayAfterAscension(year); + int monthAT = this.monthHold; + int dayAT = this.dayHold; + boolean direction = this.direction(day, month, year, dayAT, monthAT, year); + if(!direction)year++; + return sundayAfterAscension(year); + } + + // Returns date of Sunday after Ascension Thursday for the entered year + // See easterDay() for limitations of the method + public String sundayAfterAscension(int year){ + this.ascensionThursday(year); + int monthAT = this.monthHold; + int dayAT = this.dayHold + 3; + int dayCheck1 = monthDays[monthAT-1]; + if(this.leapYear(year) && monthAT==2)dayCheck1++; + if(dayAT>dayCheck1){ + dayAT = dayAT - dayCheck1; + monthAT += 1; + } + + this.dayHold = dayAT; + this.monthHold = monthAT; + this.yearHold = year; + this.dayNameHold = "Sunday"; + + return "Sunday, " + dayAT + " " + months[monthAT-1] + " " + year; + } + + // Returns date of next Whit Sunday (Pentecost) + // See easterDay() for limitations of the method + public String whitSunday(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.whitSunday(year); + int monthWS = this.monthHold; + int dayWS = this.dayHold; + boolean direction = this.direction(day, month, year, dayWS, monthWS, year); + if(!direction)year++; + return whitSunday(year); + } + + // Returns date of Whit Sunday (Pentecost)for the entered year + // See easterDay() for limitations of the method + public String whitSunday(int year){ + this.easterSunday(year); + int dayWS = this.easterDay + 49; + int monthWS = this.easterMonth; + int dayCheck1 = monthDays[monthWS-1]; + if(this.leapYear(year) && monthWS==2)dayCheck1++; + int dayCheck2 = monthDays[monthWS]; + if(this.leapYear(year) && monthWS==1)dayCheck2++; + + if(dayWS>(dayCheck1+dayCheck2)){ + dayWS -= (dayCheck1 + dayCheck2) ; + monthWS += 2; + } + else{ + if(dayWS>dayCheck1){ + dayWS -= dayCheck1 ; + monthWS += 1; + } + } + this.dayHold = dayWS; + this.monthHold = monthWS; + this.yearHold = year; + this.dayNameHold = "Sunday"; + + return "Sunday, " + dayWS + " " + months[this.monthHold-1] + " " + year; + } + + // Returns date of next Mother's Day (Mothering Sunday) in the UK + // See easterDay() for limitations of the method + public String mothersDayUK(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.mothersDayUK(year); + int monthMS = this.monthHold; + int dayMS = this.dayHold; + boolean direction = this.direction(day, month, year, dayMS, monthMS, year); + if(!direction)year++; + return mothersDayUK(year); + } + + // Returns date of Mother's Day (Mothering Sunday) in the UK for the entered year + // See easterDay() for limitations of the method + public String mothersDayUK(int year){ + this.ashWednesday(year); + int dayMS = this.dayHold + 25; + int monthMS = this.monthHold; + int dayCheck = monthDays[monthMS-1]; + if(this.leapYear(year) && monthMS==2)dayCheck++; + if(dayMS>dayCheck){ + dayMS -= dayCheck; + monthMS++; + } + this.dayHold = dayMS; + this.monthHold = monthMS; + this.yearHold = year; + this.dayNameHold = "Sunday"; + + return "Sunday, " + dayMS + " " + months[this.monthHold-1] + " " + year; + } + + // Returns date of next Mothers Day in the US + public String mothersDayUS(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.mothersDayUS(year); + boolean direction = this.direction(day, month, year, this.dayHold, this.monthHold, year); + if(!direction)year++; + return mothersDayUS(year); + } + + // Returns date of Mother's Day (Mothering Sunday) in the US for the entered year + public String mothersDayUS(int year){ + String dayMSN = this.getDayOfDate(1, "May", year); + int monthMS = 5; + int dayOwI = this.getDayOfTheWeekAsInteger(dayMSN) + 1; + int dayMS = 0; + if(dayOwI==1){ + dayMS = dayOwI + 7; + } + else{ + dayMS = 16 - dayOwI; + } + this.dayHold = dayMS; + this.monthHold = monthMS; + this.yearHold = year; + this.dayNameHold = "Sunday"; + + return "Sunday, " + dayMS + " May " + year; + } + + // Returns date of next Father's Day + public String fathersDay(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.fathersDay(year); + boolean direction = this.direction(day, month, year, this.dayHold, this.monthHold, year); + if(!direction)year++; + return fathersDay(year); + } + + // Returns date of Father's Day for the entered year + public String fathersDay(int year){ + String dayMSN = this.getDayOfDate(1, "June", year); + int monthFD = 6; + int dayOwI = this.getDayOfTheWeekAsInteger(dayMSN) + 1; + int dayFD = 0; + if(dayOwI==1){ + dayFD = dayOwI + 14; + } + else{ + dayFD = 23 - dayOwI; + } + this.dayHold = dayFD; + this.monthHold = monthFD; + this.yearHold = year; + this.dayNameHold = "Sunday"; + + return "Sunday, " + dayFD + " June " + year; + } + + // Returns date of next Christmas Day + public String christmasDay(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 25, 12, year); + if(!direction)year++; + return christmasDay(year); + } + + // Returns date of Christmas Day for the entered year + public String christmasDay(int year){ + String day = this.getDayOfDate(25, 12, year); + this.dayHold = 25; + this.monthHold = 12; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 25 December " + year; + } + + // Returns date of next New Year's Day + public String newYearsDay(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 1, 1, year); + if(!direction)year++; + return newYearsDay(year); + } + + // Returns date of New Year's Day for the entered year + public String newYearsDay(int year){ + String day = this.getDayOfDate(1, 1, year); + this.dayHold = 1; + this.monthHold = 1; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 1 January " + year; + } + + // Returns date of next Epiphany day + public String epiphany(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 6, 1, year); + if(!direction)year++; + return epiphany(year); + } + + // Returns date of Epiphany day for the entered year + public String epiphany(int year){ + String day = this.getDayOfDate(6, 1, year); + this.dayHold = 6; + this.monthHold = 1; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 6 January " + year; + } + + // Returns date of next Sunday after Epiphany day + public String sundayAfterEpiphany(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + String dayName = this.getDayOfDate(6, 1, year); + int dayI = this.getDayOfTheWeekAsInteger(dayName); + int day6plus = 6; + if(dayI>0)day6plus += (7 - dayI); + boolean direction = this.direction(day, month, year, day6plus, 1, year); + if(!direction)year++; + return sundayAfterEpiphany(year); + } + + // Returns date of Sunday after Epiphany day for the entered year + public String sundayAfterEpiphany(int year){ + String dayName = this.getDayOfDate(6, 1, year); + int dayI = this.getDayOfTheWeekAsInteger(dayName); + int day6plus = 6; + if(dayI>0)day6plus += (7 - dayI); + this.dayHold = day6plus; + this.monthHold = 1; + this.yearHold = year; + this.dayNameHold = "Sunday"; + + return "Sunday, " + day6plus + " January " + year; + } + + // Returns date of the next Feast of the Annunciation + public String annunciation(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 25, 3, year); + if(!direction)year++; + return annunciation(year); + } + // Returns date of the Feast of the Annunciation for the entered year + public String annunciation(int year){ + String day = this.getDayOfDate(25, 3, year); + this.dayHold = 25; + this.monthHold = 3; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 25 March " + year; + } + + // Returns date of the next Feast of the Assumption + public String assumption(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 15, 8, year); + if(!direction)year++; + return assumption(year); + } + + // Returns date of the Feast of the Assumption for the entered year + public String assumption(int year){ + String day = this.getDayOfDate(15, 8, year); + this.dayHold = 15; + this.monthHold = 8; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 15 August " + year; + } + + // Returns date of the next Feast of the Nativity of the Blessed Virgin + public String nativityBlessedVirgin(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 8, 9, year); + if(!direction)year++; + return nativityBlessedVirgin(year); + } + + // Returns date of the Feast of the Nativity of the Blessed Virgin for the entered year + public String nativityBlessedVirgin(int year){ + String day = this.getDayOfDate(8, 9, year); + this.dayHold = 8; + this.monthHold = 9; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 8 September " + year; + } + + // Returns date of the next Feast of the Immaculate Conception + public String immaculateConception(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 8, 12, year); + if(!direction)year++; + return immaculateConception(year); + } + + // Returns date of the Feast of the Immaculate Conception for the entered year + public String immaculateConception(int year){ + String day = this.getDayOfDate(8, 12, year); + this.dayHold = 8; + this.monthHold = 12; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 8 December " + year; + } + + // Returns date of the next Feast of the Purification of the Virgin + // [Candlemas, Feast of the Presentation of Jesus at the Temple] + public String purification(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 2, 2, year); + if(!direction)year++; + return purification(year); + } + + public String presentation(){ + return this.purification(); + } + + public String candlemas(){ + return this.purification(); + } + + // Returns date of the next Feast of the Purification of the Virgin + // [Candlemas, Feast of the Presentation of Jesus at the temple] + public String purification(int year){ + String day = this.getDayOfDate(2, 2, year); + this.dayHold = 2; + this.monthHold = 2; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 2 February " + year; + } + + public String presentation(int year){ + return this.purification(year); + } + + public String candlemas(int year){ + return this.purification(year); + } + + // Returns date of the next Feast of the Transfiguration of Christ + public String transfiguration(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 6, 8, year); + if(!direction)year++; + return transfiguration(year); + } + + // Returns date of the Feast of the Transfiguration of Christ for the entered year + public String transfiguration(int year){ + String day = this.getDayOfDate(6, 8, year); + this.dayHold = 6; + this.monthHold = 8; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 6 August " + year; + } + + // Returns date of next Remembrance Sunday + public String remembranceSunday(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + this.remembranceSunday(year); + int monthRS = this.monthHold; + int dayRS = this.dayHold; + boolean direction = this.direction(day, month, year, dayRS, monthRS, year); + if(!direction)year++; + return remembranceSunday(year); + } + + // Returns date of Remembrance Sunday for the entered year + public String remembranceSunday(int year){ + int monthRS = 11; + int dayRS = 11; + String dayNameRS = this.getDayOfDate(11, 11, year); + int dayRSI = this.getDayOfTheWeekAsInteger(dayNameRS); + if(dayRSI<4){ + dayRS -= dayRSI; + if(dayRS<1){ + int dayCheck = monthDays[monthRS-2]; + if(this.leapYear(year) && monthRS==3)dayCheck++; + dayRS = dayCheck + dayRS; + monthRS--; + } + } + else{ + dayRS += (7 - dayRSI); + int dayCheck = monthDays[monthRS-1]; + if(this.leapYear(year) && monthRS==2)dayCheck++; + if(dayRS>dayCheck){ + dayRS = dayRS - dayCheck; + monthRS++; + } + } + + this.dayHold = dayRS; + this.monthHold = monthRS; + this.yearHold = year; + this.dayNameHold = "Sunday"; + + return "Sunday, " + dayRS + " " + months[monthRS-1] + " " + year; + } + + + // Returns date of next Holocaust Memorial Day + public String holocaustMemorialDay(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 27, 1, year); + if(!direction)year++; + return holocaustMemorialDay(year); + } + + // Returns date of Holocaust Memorial Day for the entered year + public String holocaustMemorialDay(int year){ + String day = this.getDayOfDate(27, 1, year); + this.dayHold = 25; + this.monthHold = 12; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 27 January " + year; + } + + // Returns date of next St Patrick's Day + public String saintPatricksDay(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 17, 3, year); + if(!direction)year++; + return saintPatricksDay(year); + } + + // Returns date of St Patrick's Day for the entered year + public String saintPatricksDay(int year){ + String day = this.getDayOfDate(17, 3, year); + this.dayHold = 17; + this.monthHold = 3; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 17 March " + year; + } + + // Returns date of next St Brigid's Day + public String saintBrigidsDay(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 1, 2, year); + if(!direction)year++; + return saintBrigidsDay(year); + } + + // Returns date of St Brigid's Day for the entered year + public String saintBrigidsDay(int year){ + String day = this.getDayOfDate(1, 2, year); + this.dayHold = 1; + this.monthHold = 2; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 1 February " + year; + } + + // Returns date of next St Colm Cille's (St Columba's)Day + public String saintColmCillesDay(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 9, 6, year); + if(!direction)year++; + return saintColmCillesDay(year); + } + + public String saintColumbasDay(){ + return this.saintColmCillesDay(); + } + + public String saintColmcillesDay(){ + return this.saintColmCillesDay(); + } + + // Returns date of St Colm Cille's (St Columba's) Day for the entered year + public String saintColmCillesDay(int year){ + String day = this.getDayOfDate(9, 6, year); + this.dayHold = 9; + this.monthHold = 6; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 9 June " + year; + } + + public String saintColumbasDay(int year){ + return this.saintColmCillesDay(year); + } + + public String saintColmcillesDay(int year){ + return this.saintColmCillesDay(year); + } + + // Returns date of next St Georges's day + public String saintGeorgesDay(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 23, 4, year); + if(!direction)year++; + return saintGeorgesDay(year); + } + + // Returns date of St George's day for the entered year + public String saintGeorgesDay(int year){ + String day = this.getDayOfDate(23, 4, year); + this.dayHold = 23; + this.monthHold = 4; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 23 April " + year; + } + + // Returns date of next St Andrew's day + public String saintAndrewsDay(){int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 30, 11, year); + if(!direction)year++; + return saintAndrewsDay(year); + } + + // Returns date of St Andrew's day for the entered year + public String saintAndrewsDay(int year){ + String day = this.getDayOfDate(30, 11, year); + this.dayHold = 30; + this.monthHold = 11; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 30 November " + year; + } + + // Returns date of next St David's day + public String saintDavidsDay(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 1, 3, year); + if(!direction)year++; + return saintDavidsDay(year); + } + + // Returns date of St David's day for the entered year + public String saintDavidsDay(int year){ + String day = this.getDayOfDate(1, 3, year); + this.dayHold = 1; + this.monthHold = 3; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 1 March " + year; + } + + // Returns date of next St Stephen's day + public String saintStephensDay(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 26, 12, year); + if(!direction)year++; + return saintStephensDay(year); + } + + // Returns date of St Stephen's day for the entered year + public String saintStephensDay(int year){ + String day = this.getDayOfDate(26, 12, year); + this.dayHold = 26; + this.monthHold = 12; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 26 December " + year; + } + + // Returns date of next St Valentine's day + public String saintValentinesDay(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 14, 2, year); + if(!direction)year++; + return saintValentinesDay(year); + } + + // Returns date of St Valentines's day for the entered year + public String saintValentinesDay(int year){ + String day = this.getDayOfDate(14, 2, year); + this.dayHold = 14; + this.monthHold = 2; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 14 February " + year; + } + + + // Returns date of next Burns' night + public String burnsNight(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 25, 1, year); + if(!direction)year++; + return burnsNight(year); + } + + // Returns date of Burns night for the entered year + public String burnsNight(int year){ + String day = this.getDayOfDate(25, 1, year); + this.dayHold = 25; + this.monthHold = 1; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 25 January " + year; + } + + // Returns date of next Twelfth of July + public String twelfthJuly(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 12, 7, year); + if(!direction)year++; + return twelfthJuly(year); + } + + // Returns date of the Twelfth of July for the entered year + public String twelfthJuly(int year){ + String day = this.getDayOfDate(12, 7, year); + this.dayHold = 12; + this.monthHold = 7; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 12 July " + year; + } + + // Returns date of next Fourth of July (US Independence Day) + public String fourthJuly(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 12, 7, year); + if(!direction)year++; + return fourthJuly(year); + } + + // Returns date of the Fourth of July (US Independence Day)for the entered year + public String fourthJuly(int year){ + String day = this.getDayOfDate(4, 7, year); + this.dayHold = 4; + this.monthHold = 7; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 4 July " + year; + } + + // Returns date of next US Thanksgiving Day + public String thanksgivingDay(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + + String day1 = this.getDayOfDate(1, "November", year); + int day1I = this.getDayOfTheWeekAsInteger(day1) + 1; + int day2I = 6 - day1I; + if(day2I<=0)day2I += 7; + day2I += 14; + boolean direction = this.direction(day, month, year, day2I, 11, year); + if(direction){ + return "Thursday, " + day2I + " November " + year; + } + else{ + return thanksgivingDay(++year); + } + } + + // Returns date of the US Thanksgiving Day + public String thanksgivingDay(int year){ + String day1 = this.getDayOfDate(1, "November", year); + int day1I = this.getDayOfTheWeekAsInteger(day1) + 1; + int day2I = 6 - day1I; + if(day2I<=0)day2I += 7; + day2I += 14; + this.dayHold = day2I; + this.monthHold = 11; + this.yearHold = year; + this.dayNameHold = "Thursday"; + return "Thursday, " + day2I + " November " + year; + } + + // Returns date of next Commonwealth Day + public String commonwealthDay(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + + String day1 = this.getDayOfDate(1, "March", year); + int day1I = this.getDayOfTheWeekAsInteger(day1); + + int day2I = 0; + if(day1I>1){ + day2I = 15 - day1I; + } + else{ + if(day1I==0){ + day2I = 8; + } + else{ + day2I = 9; + } + } + boolean direction = this.direction(day, month, year, day2I, 3, year); + if(direction){ + this.dayHold = day2I; + this.monthHold = 3; + this.yearHold = year; + this.dayNameHold = "Monday"; + return "Monday, " + day2I + " November " + year; + } + else{ + return commonwealthDay(++year); + } + } + + // Returns date of the Commonwealth Day + public String commonwealthDay(int year){ + String day1 = this.getDayOfDate(1, "March", year); + int day1I = this.getDayOfTheWeekAsInteger(day1); + + int day2I = 0; + if(day1I>1){ + day2I = 16 - day1I; + } + else{ + if(day1I==0){ + day2I = 9; + } + else{ + day2I = 8; + } + } + this.dayHold = day2I; + this.monthHold = 3; + this.yearHold = year; + this.dayNameHold = "Monday"; + return "Monday, " + day2I + " March " + year; + } + + // Returns date of next Armed Forces Day (UK Veterans' Day) + public String armedForcesDay(){ + int year = this.getYear(); + int month = this.getMonthAsInteger(); + int day = this.getDayOfTheMonth(); + boolean direction = this.direction(day, month, year, 27, 6, year); + if(!direction)year++; + return armedForcesDay(year); + } + + public String veteransDayUK(){ + return this.armedForcesDay(); + } + + // Returns date of the Armed Forces Day (UK Veterans' Day)for the entered year + public String armedForcesDay(int year){ + String day = this.getDayOfDate(27, 6, year); + this.dayHold = 27; + this.monthHold = 6; + this.yearHold = year; + this.dayNameHold = day; + return day + ", 27 June " + year; + } + + public String veteransDayUK(int year){ + return this.armedForcesDay(year); + } + + // Returns true if year (argument) is a leap year + public boolean leapYear(int year){ + boolean test = false; + + if(year%4 != 0){ + test = false; + } + else{ + if(year%400 == 0){ + test=true; + } + else{ + if(year%100 == 0){ + test=false; + } + else{ + test=true; + } + } + } + return test; + } +} + diff --git a/src/main/java/flanagan/optics/GratingCoupler.java b/src/main/java/flanagan/optics/GratingCoupler.java new file mode 100755 index 0000000000000000000000000000000000000000..e916c72f7bdfc28670c1ba2e0f915efbbff67be6 --- /dev/null +++ b/src/main/java/flanagan/optics/GratingCoupler.java @@ -0,0 +1,629 @@ +/* +* GratingCoupler Class +* +* Methods for: +* determining the refractive index of a waveguiding thin film +* in an asymmetric slab waveguide from the grating coupling angle and the core layer thickness +* and for obtaining the normalised propagation vector versus guiding layer thickness +* +* determinimg the refractive index of the superstrate [analyte solution in a grating coupler sensor] +* +* obtaining the normalised propagation vector versus guiding layer thickness +* dispersion curve for an asymmetric slab waveguide +* +* This is a subclass of the superclasses PlanarWaveguideCoupler +* +* Author: Dr Michael Thomas Flanagan. +* +* Created: 28 April 2006 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/GratingCoupler.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) April 2006 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.optics; + +import flanagan.math.Fmath; +import flanagan.analysis.ErrorProp; +import flanagan.plot.*; +import flanagan.optics.*; + +public class GratingCoupler extends PlanarWaveguide{ + + // CLASS VARIABLES + + private double[] thicknessesTE = null; // thicknesses for experimental TE mode thimeasurements + private double[] anglesDegTE = null; // coupling angles, in degrees, for experimental TE mode measurements + private double[] anglesRadTE = null; // coupling angles, in radians, for experimental TE mode measurements + private double[] errorsDegTE = null; // errors in coupling angles, in degrees, for experimental TE mode measurements + private double[] errorsRadTE = null; // errors in coupling angles, in radians, for experimental TE mode measurements + private double[] modeNumbersTE = null; // mode numbers for experimental TE mode measurements + private double[] effectiveRefractiveIndicesTE = null; // effective refractive indices for TE mode measurements + private double[] effectiveErrorsTE = null; // propagated errors for effective refractive indices for TE mode measurements + private int numberOfTEmeasurementsGrating = 0; // number of TE mode thickness measurement + private boolean setMeasurementsTEgrating = false; // = true when TE mode measurements entered + private boolean setTEerrors = false; // = true if TE mode errors are set + + private boolean calcEffectiveDone = false; // = true when effective refractive indices calculated + + private double[] thicknessesTM = null; // thicknesses for experimental TM mode thimeasurements + private double[] anglesDegTM = null; // coupling angles, in degrees, for experimental TM mode measurements + private double[] anglesRadTM = null; // coupling angles, in radians, for experimental TM mode measurements + private double[] errorsDegTM = null; // errors in coupling angles, in degrees, for experimental TM mode measurements + private double[] errorsRadTM = null; // errors in coupling angles, in radians, for experimental TM mode measurements + private double[] modeNumbersTM = null; // mode numbers for experimental TM mode measurements + private double[] effectiveRefractiveIndicesTM = null; // effective refractive indices for TM mode measurements + private double[] effectiveErrorsTM = null; // propagated errors for effective refractive indices for TM mode measurements + private int numberOfTMmeasurementsGrating = 0; // number of TM mode thickness measurement + private boolean setMeasurementsTMgrating = false; // = true when TM mode measurements entered + private boolean setTMerrors = false; // = true if TM mode errors are set + + private int numberOfMeasurementsGrating = 0; // total number of thickness measurements entered + private boolean setMeasurementsGrating = false; // = true when TE and/or TM mode measurements entered + + private double gratingPitch = 0.0D; // Grating pitch, metres + private boolean setGratingPitch = false; // = true when grating pitch entered + private int[] gratingOrderTE = null; // Grating order for each TE mode measurement, default value = 1 + private boolean setGratingOrderTE = false; // = true when TE mode grating orders entered + private int[] gratingOrderTM = null; // Grating order for each TM mode measurement, default value = 1 + private boolean setGratingOrderTM = false; // = true when TM mode grating orders entered + + private double superstrateRI = 0.0; // Superstrate refractive index + private boolean setSuperstrateRI = false; // equals true when superstrate refractice index entered + + // CONSTRUCTOR + public GratingCoupler(){ + } + + + // GRATING + // Enter pitch + public void setGratingPitch(double pitch){ + this.gratingPitch = pitch; + this.setGratingPitch = true; + if(this.setMeasurementsGrating && super.setWavelength)this.calcEffectiveRefractiveIndices(); + } + + // Enter grating orders for TE measurements + public void setSetTEmodeGratingOrder(int[] order){ + this.gratingOrderTE = order; + int m = order.length; + if(this.setMeasurementsTEgrating)if(m!=this.numberOfTEmeasurementsGrating)throw new IllegalArgumentException("Number of grating orders entered, " + m + ", is not equal to the number of measurements previously entered, " + this.numberOfTEmeasurementsGrating); + if(this.setMeasurementsGrating && this.setGratingPitch && super.setWavelength)this.calcEffectiveRefractiveIndices(); + } + + // Enter grating orders for TM measurements + public void setSetTMmodeGratingOrder(int[] order){ + this.gratingOrderTM = order; + int m = order.length; + if(this.setMeasurementsTMgrating)if(m!=this.numberOfTMmeasurementsGrating)throw new IllegalArgumentException("Number of grating orders entered, " + m + ", is not equal to the number of measurements previously entered, " + this.numberOfTEmeasurementsGrating); + if(this.setMeasurementsGrating && this.setGratingPitch && super.setWavelength)this.calcEffectiveRefractiveIndices(); + } + + // Enter superstrate refractive index (overrides superclass method) + public void setSuperstrateRefractiveIndex(double index){ + if(this.calcEffectiveDone)this.clearData(); + this.superstrateRI = index; + super.superstrateRefractiveIndex = index; + this.setSuperstrateRI = true; + if(this.setMeasurementsGrating && this.setGratingPitch && super.setWavelength)this.calcEffectiveRefractiveIndices(); + } + + + // Return analyte solution refractive index + public double getAnalyteSolutionRefractiveIndex(){ + return super.getSuperstrateRefractiveIndex(); + } + + // Return analyte solution refractive index + public double getStandardDeviationAnalyteSolutionRefractiveIndex(){ + return super.getStandardDeviationSuperstrateRefractiveIndex(); + } + + + // THICKNESS (metres), COUPLING ANGLE (degrees) AND MODE NUMBER DATA + // Enter TE mode data for a single measurement without error + public void enterTEmodeData(double thickness, double angle, double modeNumber){ + if(this.setMeasurementsTEgrating){ + if(this.setTEerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTEmeasurementsGrating + 1; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++)hold[i] = this.thicknessesTE[i]; + hold[this.numberOfTEmeasurementsGrating] = thickness; + this.thicknessesTE = hold; + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++)hold[i] = this.anglesDegTE[i]; + hold[this.numberOfTEmeasurementsGrating] = angle; + this.anglesDegTE = hold; + this.anglesRadTE = hold; + this.errorsDegTE = hold; + this.errorsRadTE = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTE[i] = Math.toRadians(this.anglesDegTE[i]); + this.errorsDegTE[i] = 0.0D; + this.errorsRadTE[i] = 0.0D; + } + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++)hold[i] = this.modeNumbersTE[i]; + hold[this.numberOfTEmeasurementsGrating] = modeNumber; + this.numberOfTEmeasurementsGrating = nNew; + } + else{ + this.thicknessesTE = new double[1]; + this.thicknessesTE[0] = thickness; + this.anglesDegTE = new double[1]; + this.anglesDegTE[0] = angle; + this.anglesRadTE = new double[1]; + this.anglesRadTE[0] = Math.toRadians(angle); + this.errorsDegTE = new double[1]; + this.errorsDegTE[0] = 0.0D; + this.errorsRadTE = new double[1]; + this.errorsRadTE[0] = 0.0D; + this.modeNumbersTE = new double[1]; + this.modeNumbersTE[0] = modeNumber; + this.numberOfTEmeasurementsGrating = 1; + } + this.numberOfMeasurementsGrating = this.numberOfTEmeasurementsGrating + this.numberOfTMmeasurementsGrating; + this.setMeasurementsTEgrating = true; + this.setMeasurementsGrating = true; + if(this.setGratingPitch && super.setWavelength)this.calcTEmodeEffectiveRefractiveIndices(); + } + + + + // Enter TM mode data for a single measurement without error + public void enterTMmodeData(double thickness, double angle, double modeNumber){ + if(this.setMeasurementsTMgrating){ + if(this.setTMerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTMmeasurementsGrating + 1; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++)hold[i] = this.thicknessesTM[i]; + hold[this.numberOfTMmeasurementsGrating] = thickness; + this.thicknessesTM = hold; + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++)hold[i] = this.anglesDegTM[i]; + hold[this.numberOfTMmeasurementsGrating] = angle; + this.anglesDegTM = hold; + this.anglesRadTM = hold; + this.errorsDegTM = hold; + this.errorsRadTM = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTM[i] = Math.toRadians(this.anglesDegTM[i]); + this.errorsDegTM[i] = 0.0D; + this.errorsRadTM[i] = 0.0D; + } + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++)hold[i] = this.modeNumbersTM[i]; + hold[this.numberOfTMmeasurementsGrating] = modeNumber; + this.numberOfTMmeasurementsGrating = nNew; + } + else{ + this.thicknessesTM = new double[1]; + this.thicknessesTM[0] = thickness; + this.anglesDegTM = new double[1]; + this.anglesDegTM[0] = angle; + this.anglesRadTM = new double[1]; + this.anglesRadTM[0] = Math.toRadians(angle); + this.errorsDegTM = new double[1]; + this.errorsDegTM[0] = 0.0D; + this.errorsRadTM = new double[1]; + this.errorsRadTM[0] = 0.0D; + this.modeNumbersTM = new double[1]; + this.modeNumbersTM[0] = modeNumber; + this.numberOfTMmeasurementsGrating = 1; + } + this.numberOfMeasurementsGrating = this.numberOfTEmeasurementsGrating + this.numberOfTMmeasurementsGrating; + this.setMeasurementsTMgrating = true; + this.setMeasurementsGrating = true; + if(this.setGratingPitch && super.setWavelength)this.calcTMmodeEffectiveRefractiveIndices(); + + } + + // Enter TE mode data for a range of measurements without errors + public void enterTEmodeData(double[] thicknesses, double[] angles, double[] modeNumbers){ + int o = thicknesses.length; + int n = angles.length; + if(n!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of coupling angles, " + n); + int m = modeNumbers.length; + if(m!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of mode numbers, " + m); + + if(this.setMeasurementsTEgrating){ + if(this.setTEerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTEmeasurementsGrating + o; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++)hold[i] = this.thicknessesTE[i]; + for(int i=0; i<o; i++)hold[this.numberOfTEmeasurementsGrating+i] = thicknesses[i]; + this.thicknessesTE = hold; + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++)hold[i] = this.anglesDegTE[i]; + for(int i=0; i<o; i++)hold[this.numberOfTEmeasurementsGrating+i] = angles[i]; + this.anglesDegTE = hold; + this.anglesRadTE = hold; + this.errorsDegTE = hold; + this.errorsRadTE = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTE[i] = Math.toRadians(this.anglesDegTE[i]); + this.errorsDegTE[i] = 0.0D; + this.errorsRadTE[i] = 0.0D; + } + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++)hold[i] = this.modeNumbersTE[i]; + for(int i=0; i<o; i++)hold[this.numberOfTEmeasurementsGrating+i] = modeNumbers[i]; + this.numberOfTEmeasurementsGrating = nNew; + } + else{ + this.numberOfTEmeasurementsGrating = o; + this.thicknessesTE = thicknesses; + this.anglesDegTE = angles; + this.anglesRadTE = new double[o]; + this.errorsDegTE = new double[o]; + this.errorsRadTE = new double[o]; + for(int i=0; i<o; i++){ + this.anglesRadTE[i] = Math.toRadians(angles[i]); + this.errorsDegTE[i] = 0.0D; + this.errorsRadTE[i] = 0.0D; + } + this.modeNumbersTE = modeNumbers; + } + this.numberOfMeasurementsGrating = this.numberOfTEmeasurementsGrating + this.numberOfTMmeasurementsGrating; + this.setMeasurementsTEgrating = true; + this.setMeasurementsGrating = true; + if(this.setGratingPitch && super.setWavelength)this.calcTEmodeEffectiveRefractiveIndices(); + + } + + // Enter TM mode data for a range of measurements without errors + public void enterTMmodeData(double[] thicknesses, double[] angles, double[] modeNumbers){ + int o = thicknesses.length; + int n = angles.length; + if(n!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of coupling angles, " + n); + int m = modeNumbers.length; + if(m!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of mode numbers, " + m); + + if(this.setMeasurementsTMgrating){ + if(this.setTMerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTMmeasurementsGrating + o; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++)hold[i] = this.thicknessesTM[i]; + for(int i=0; i<o; i++)hold[this.numberOfTMmeasurementsGrating+i] = thicknesses[i]; + this.thicknessesTM = hold; + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++)hold[i] = this.anglesDegTM[i]; + for(int i=0; i<o; i++)hold[this.numberOfTMmeasurementsGrating+i] = angles[i]; + this.anglesDegTM = hold; + this.anglesRadTM = hold; + this.errorsDegTM = hold; + this.errorsRadTM = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTM[i] = Math.toRadians(this.anglesDegTM[i]); + this.errorsDegTM[i] = 0.0D; + this.errorsRadTM[i] = 0.0D; + } + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++)hold[i] = this.modeNumbersTM[i]; + for(int i=0; i<o; i++)hold[this.numberOfTMmeasurementsGrating+i] = modeNumbers[i]; + this.numberOfTMmeasurementsGrating = nNew; + } + else{ + this.numberOfTMmeasurementsGrating = o; + this.thicknessesTM = thicknesses; + this.anglesDegTM = angles; + this.anglesRadTM = new double[o]; + this.errorsDegTM = new double[o]; + this.errorsRadTM = new double[o]; + for(int i=0; i<o; i++){ + this.anglesRadTM[i] = Math.toRadians(angles[i]); + this.errorsDegTM[i] = 0.0D; + this.errorsRadTM[i] = 0.0D; + } + this.modeNumbersTM = modeNumbers; + } + this.numberOfMeasurementsGrating = this.numberOfTEmeasurementsGrating + this.numberOfTMmeasurementsGrating; + this.setMeasurementsTMgrating = true; + this.setMeasurementsGrating = true; + if(this.setGratingPitch && super.setWavelength)this.calcTMmodeEffectiveRefractiveIndices(); + } + + // Enter TE mode data for a single measurement with error + public void enterTEmodeData(double thickness, double angle, double error, double modeNumber){ + if(this.setMeasurementsTEgrating){ + if(!this.setTEerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTEmeasurementsGrating + 1; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++)hold[i] = this.thicknessesTE[i]; + hold[this.numberOfTEmeasurementsGrating] = thickness; + this.thicknessesTE = hold; + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++)hold[i] = this.anglesDegTE[i]; + hold[this.numberOfTEmeasurementsGrating] = angle; + this.anglesDegTE = hold; + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++)hold[i] = this.errorsDegTE[i]; + hold[this.numberOfTEmeasurementsGrating] = error; + this.errorsDegTE = hold; + this.anglesRadTE = hold; + this.errorsRadTE = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTE[i] = Math.toRadians(this.anglesDegTE[i]); + this.errorsRadTE[i] = Math.toRadians(this.errorsDegTE[i]); + } + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++)hold[i] = this.modeNumbersTE[i]; + hold[this.numberOfTEmeasurementsGrating] = modeNumber; + this.numberOfTEmeasurementsGrating = nNew; + } + else{ + this.thicknessesTE = new double[1]; + this.thicknessesTE[0] = thickness; + this.anglesDegTE = new double[1]; + this.anglesDegTE[0] = angle; + this.anglesRadTE = new double[1]; + this.anglesRadTE[0] = Math.toRadians(angle); + this.errorsDegTE = new double[1]; + this.errorsDegTE[0] = error; + this.errorsRadTE = new double[1]; + this.errorsRadTE[0] = Math.toRadians(error); + this.modeNumbersTE = new double[1]; + this.modeNumbersTE[0] = modeNumber; + this.numberOfTEmeasurementsGrating = 1; + } + this.numberOfMeasurementsGrating = this.numberOfTEmeasurementsGrating + this.numberOfTMmeasurementsGrating; + this.setMeasurementsTEgrating = true; + this.setTEerrors = true; + this.setMeasurementsGrating = true; + if(this.setGratingPitch && super.setWavelength)this.calcTEmodeEffectiveRefractiveIndices(); + } + + + + // Enter TM mode data for a single measurement with error + public void enterTMmodeData(double thickness, double angle, double error, double modeNumber){ + if(this.setMeasurementsTMgrating){ + if(!this.setTMerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTMmeasurementsGrating + 1; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++)hold[i] = this.thicknessesTM[i]; + hold[this.numberOfTMmeasurementsGrating] = thickness; + this.thicknessesTM = hold; + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++)hold[i] = this.anglesDegTM[i]; + hold[this.numberOfTMmeasurementsGrating] = angle; + this.anglesDegTM = hold; + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++)hold[i] = this.errorsDegTM[i]; + hold[this.numberOfTMmeasurementsGrating] = error; + this.errorsDegTM = hold; + this.anglesRadTM = hold; + this.errorsRadTM = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTM[i] = Math.toRadians(this.anglesDegTM[i]); + this.errorsRadTM[i] = Math.toRadians(this.errorsDegTM[i]); + } + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++)hold[i] = this.modeNumbersTM[i]; + hold[this.numberOfTMmeasurementsGrating] = modeNumber; + this.numberOfTMmeasurementsGrating = nNew; + } + else{ + this.thicknessesTM = new double[1]; + this.thicknessesTM[0] = thickness; + this.anglesDegTM = new double[1]; + this.anglesDegTM[0] = angle; + this.anglesRadTM = new double[1]; + this.anglesDegTM[0] = Math.toRadians(angle); + this.errorsDegTM = new double[1]; + this.errorsDegTM[0] = error; + this.errorsRadTM = new double[1]; + this.errorsDegTM[0] = Math.toRadians(error); + this.modeNumbersTM = new double[1]; + this.modeNumbersTM[0] = modeNumber; + this.numberOfTMmeasurementsGrating = 1; + } + this.numberOfMeasurementsGrating = this.numberOfTEmeasurementsGrating + this.numberOfTMmeasurementsGrating; + this.setMeasurementsTMgrating = true; + this.setTMerrors = true; + this.setMeasurementsGrating = true; + if(this.setGratingPitch && super.setWavelength)this.calcTMmodeEffectiveRefractiveIndices(); + } + + // Enter TE mode data for a range of measurements with errors + public void enterTEmodeData(double[] thicknesses, double[] angles, double[] errors, double[] modeNumbers){ + int o = thicknesses.length; + int n = angles.length; + if(n!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of coupling angles, " + n); + int m = modeNumbers.length; + if(m!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of mode numbers, " + m); + + if(this.setMeasurementsTEgrating){ + if(!this.setTEerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTEmeasurementsGrating + o; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++)hold[i] = this.thicknessesTE[i]; + for(int i=0; i<o; i++)hold[this.numberOfTEmeasurementsGrating+i] = thicknesses[i]; + this.thicknessesTE = hold; + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++)hold[i] = this.anglesDegTE[i]; + for(int i=0; i<o; i++)hold[this.numberOfTEmeasurementsGrating+i] = angles[i]; + this.anglesDegTE = hold; + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++)hold[i] = this.errorsDegTE[i]; + for(int i=0; i<o; i++)hold[this.numberOfTEmeasurementsGrating+i] = errors[i]; + this.errorsDegTE = hold; + this.anglesRadTE = hold; + this.errorsRadTE = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTE[i] = Math.toRadians(this.anglesDegTE[i]); + this.errorsRadTE[i] = Math.toRadians(this.errorsDegTE[i]); + } + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++)hold[i] = this.modeNumbersTE[i]; + for(int i=0; i<o; i++)hold[this.numberOfTEmeasurementsGrating+i] = modeNumbers[i]; + this.numberOfTEmeasurementsGrating = nNew; + } + else{ + this.numberOfTEmeasurementsGrating = o; + this.thicknessesTE = thicknesses; + this.anglesDegTE = angles; + this.anglesRadTE = new double[o]; + this.errorsDegTE = errors; + this.errorsRadTE = new double[o]; + for(int i=0; i<o; i++){ + this.anglesRadTE[i] = Math.toRadians(angles[i]); + this.errorsRadTE[i] = Math.toRadians(errors[i]); + } + this.modeNumbersTE = modeNumbers; + } + this.numberOfMeasurementsGrating = this.numberOfTEmeasurementsGrating + this.numberOfTMmeasurementsGrating; + this.setMeasurementsTEgrating = true; + this.setTEerrors = true; + this.setMeasurementsGrating = true; + if(this.setGratingPitch && super.setWavelength)this.calcTEmodeEffectiveRefractiveIndices(); + } + + // Enter TM mode data for a range of measurements without errors + public void enterTMmodeData(double[] thicknesses, double[] angles, double[] errors, double[] modeNumbers){ + int o = thicknesses.length; + int n = angles.length; + if(n!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of coupling angles, " + n); + int m = modeNumbers.length; + if(m!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of mode numbers, " + m); + + if(this.setMeasurementsTMgrating){ + if(!this.setTMerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTMmeasurementsGrating + o; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++)hold[i] = this.thicknessesTM[i]; + for(int i=0; i<o; i++)hold[this.numberOfTMmeasurementsGrating+i] = thicknesses[i]; + this.thicknessesTM = hold; + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++)hold[i] = this.anglesDegTM[i]; + for(int i=0; i<o; i++)hold[this.numberOfTMmeasurementsGrating+i] = angles[i]; + this.anglesDegTM = hold; + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++)hold[i] = this.errorsDegTM[i]; + for(int i=0; i<o; i++)hold[this.numberOfTMmeasurementsGrating+i] = errors[i]; + this.errorsDegTM = hold; + this.anglesRadTM = hold; + this.errorsRadTM = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTM[i] = Math.toRadians(this.anglesDegTM[i]); + this.errorsRadTM[i] = Math.toRadians(this.errorsDegTM[i]); + } + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++)hold[i] = this.modeNumbersTM[i]; + for(int i=0; i<o; i++)hold[this.numberOfTMmeasurementsGrating+i] = modeNumbers[i]; + this.numberOfTMmeasurementsGrating = nNew; + } + else{ + this.numberOfTMmeasurementsGrating = o; + this.thicknessesTM = thicknesses; + this.anglesDegTM = angles; + this.errorsDegTM = errors; + this.anglesRadTM = new double[o]; + this.errorsRadTM = new double[o]; + for(int i=0; i<o; i++){ + this.anglesRadTM[i] = Math.toRadians(angles[i]); + this.errorsRadTM[i] = Math.toRadians(errors[i]); + } + this.modeNumbersTM = modeNumbers; + } + this.numberOfMeasurementsGrating = this.numberOfTEmeasurementsGrating + this.numberOfTMmeasurementsGrating; + this.setMeasurementsTMgrating = true; + this.setTMerrors = true; + this.setMeasurementsGrating = true; + if(this.setGratingPitch && super.setWavelength)this.calcTMmodeEffectiveRefractiveIndices(); + } + + + // Clear entered thickness, effective refractive index and mode number data + // so new dat may be entered without it being appended to the existing data + public void clearData(){ + this.numberOfTEmeasurementsGrating = 0; + this.setMeasurementsTEgrating = false; + + this.numberOfTMmeasurementsGrating = 0; + this.setMeasurementsTMgrating = false; + + super.numberOfMeasurements = 0; + super.setMeasurements = false; + super.setWeights = false; + + super.numberOfTEmeasurements = 0; + super.setMeasurementsTE = false; + + super.numberOfTMmeasurements = 0; + super.setMeasurementsTM = false; + } + + // CALCULATION OF THE EFFECTIVE REFRACTIVE INDEX/INDICES + // Calculate all effective refractive indices + public void calcEffectiveRefractiveIndices(){ + if(this.setMeasurementsTEgrating)this.calcTEmodeEffectiveRefractiveIndices(); + if(this.setMeasurementsTMgrating)this.calcTMmodeEffectiveRefractiveIndices(); + } + + // Calculate TE mode effective refractive indices + public void calcTEmodeEffectiveRefractiveIndices(){ + this.effectiveRefractiveIndicesTE = new double[this.numberOfTEmeasurementsGrating]; + this.effectiveErrorsTE = new double[this.numberOfTEmeasurementsGrating]; + + if(!this.setSuperstrateRI){ + this.superstrateRI = RefractiveIndex.air(super.wavelength); + super.superstrateRefractiveIndex = RefractiveIndex.air(super.wavelength); + } + + if(this.setTEerrors){ + ErrorProp superRI = new ErrorProp(super.superstrateRefractiveIndex, 0.0D); + ErrorProp pitch = new ErrorProp(this.gratingPitch, 0.0D); + ErrorProp lambda = new ErrorProp(super.wavelength, 0.0D); + + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++){ + ErrorProp theta = new ErrorProp(this.anglesRadTM[i], this.errorsRadTM[i]); + ErrorProp order = new ErrorProp((double)this.gratingOrderTE[i], 0.0D); + ErrorProp calc = ErrorProp.sin(theta); + calc = calc.times(superRI); + calc = calc.plus(lambda.times(order).over(pitch)); + this.effectiveRefractiveIndicesTE[i] = calc.getValue(); + this.effectiveErrorsTE[i] = calc.getError(); + } + super.enterTEmodeData(this.thicknessesTE, this.effectiveRefractiveIndicesTE, this.effectiveErrorsTE, this.modeNumbersTE); + } + else{ + for(int i=0; i<this.numberOfTEmeasurementsGrating; i++){ + this.effectiveRefractiveIndicesTE[i] = this.superstrateRI*Math.sin(this.anglesRadTE[i]) + super.wavelength*this.gratingOrderTE[i]/this.gratingPitch; + } + super.enterTEmodeData(this.thicknessesTE, this.effectiveRefractiveIndicesTE, this.modeNumbersTE); + } + this.calcEffectiveDone = true; + } + + // Calculate TM mode effective refractive indices + public void calcTMmodeEffectiveRefractiveIndices(){ + this.effectiveRefractiveIndicesTM = new double[this.numberOfTMmeasurementsGrating]; + this.effectiveErrorsTM = new double[this.numberOfTMmeasurementsGrating]; + + if(!this.setSuperstrateRI){ + this.superstrateRI = RefractiveIndex.air(super.wavelength); + super.superstrateRefractiveIndex = RefractiveIndex.air(super.wavelength); + } + + if(this.setTMerrors){ + ErrorProp superRI = new ErrorProp(super.superstrateRefractiveIndex, 0.0D); + ErrorProp pitch = new ErrorProp(this.gratingPitch, 0.0D); + ErrorProp lambda = new ErrorProp(super.wavelength, 0.0D); + + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++){ + ErrorProp theta = new ErrorProp(this.anglesRadTM[i], this.errorsRadTM[i]); + ErrorProp order = new ErrorProp((double)this.gratingOrderTM[i], 0.0D); + ErrorProp calc = ErrorProp.sin(theta); + calc = calc.times(superRI); + calc = calc.plus(lambda.times(order).over(pitch)); + this.effectiveRefractiveIndicesTM[i] = calc.getValue(); + this.effectiveErrorsTM[i] = calc.getError(); + } + super.enterTMmodeData(this.thicknessesTM, this.effectiveRefractiveIndicesTM, this.effectiveErrorsTM, this.modeNumbersTM); + } + else{ + for(int i=0; i<this.numberOfTMmeasurementsGrating; i++){ + this.effectiveRefractiveIndicesTM[i] = this.superstrateRI*Math.sin(this.anglesRadTM[i]) + super.wavelength*this.gratingOrderTM[i]/this.gratingPitch; + } + super.enterTMmodeData(this.thicknessesTM, this.effectiveRefractiveIndicesTM, this.modeNumbersTM); + } + this.calcEffectiveDone = true; + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/optics/PlanarWaveguide.java b/src/main/java/flanagan/optics/PlanarWaveguide.java new file mode 100755 index 0000000000000000000000000000000000000000..7c634b1e39188d6289150ab4671bd2c49c5fda57 --- /dev/null +++ b/src/main/java/flanagan/optics/PlanarWaveguide.java @@ -0,0 +1,1756 @@ +/* +* PlanarWaveguide Class +* +* Methods for: +* determining the refractive index of a waveguiding thin film +* in an asymmetric slab waveguide from the effective refractive index, i.e. +* the normalised propagation vector, and the core layer thickness +* +* determinimg the refractive index of the superstrate [waveguide coupler sensor] +* +* obtaining the normalised propagation vector versus guiding layer thickness +* dispersion curve for an asymmetric slab waveguide +* +* +* This is the superclass for the subclasses PrismCoupler and GratingCoupler +* +* Author: Dr Michael Thomas Flanagan. +* +* Created: March 2006 +* Revised: 29 April 2006, 5-7 July 2008, 9 November 2009 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/PlanarWaveguide.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2006 - 2009 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + + package flanagan.optics; + +import flanagan.math.*; +import flanagan.analysis.Stat; +import flanagan.roots.*; +import flanagan.plot.*; +import flanagan.optics.RefractiveIndex; + +import java.util.ArrayList; + +public class PlanarWaveguide{ + + // CLASS VARIABLES + + protected double[][] measurementsTE = null; // experimental TE mode measurements + // [film thickness][effective refractive index][weight][mode number] + protected int numberOfTEmeasurements = 0; // number of TE mode experimental measurements + protected double[] thicknessesUsedTE = null; // TE mode thicknesses used in calculation + protected double[] calcEffectRefrIndicesTE = null; // TE mode calculated effective refractive indices for mean core refractive index + protected boolean setMeasurementsTE = false; // = true when TE mode measurements entered + protected boolean setErrorsTE = false; // = true when TE mode errors entered + protected double maximumTEmodeEffectiveRefractiveIndex = 0.0D; // Maximum TE mode effective refractive index value + protected double minimumTEmodeEffectiveRefractiveIndex = 0.0D; // Minimum TE mode effective refractive index value + protected double[][] measurementsTM = null; // experimental TM mode measurements + // [film thickness][effective refractive index][weight][mode number] + protected int numberOfTMmeasurements = 0; // number of TM mode experimental measurements + protected double[] thicknessesUsedTM = null; // TM mode thicknesses used in calculation + protected double[] calcEffectRefrIndicesTM = null; // TM mode calculated effective refractive indices for mean core refractive index + protected boolean setMeasurementsTM = false; // = true when TM mode measurements entered + protected boolean setErrorsTM = false; // = true when TM mode errors entered + protected double maximumTMmodeEffectiveRefractiveIndex = 0.0D; // Maximum TM mode effective refractive index value + protected double minimumTMmodeEffectiveRefractiveIndex = 0.0D; // Minimum TM mode effective refractive index value + protected double maximumEffectiveRefractiveIndex = 0.0D; // Maximum overall effective refractive index value + protected double minimumEffectiveRefractiveIndex = 0.0D; // Minimum overall effective refractive index value + protected int numberOfMeasurements = 0; // total number of experimental measurements + protected boolean setMeasurements = false; // = true when measurements entered + protected boolean setWeights = false; // = true when weights entered + protected boolean[] eliminatedTE = null; // = true when TE point eliminated if effective refractive index lies below physical limit (Max[sub or superstrate] + protected boolean[] eliminatedTM = null; // = true when TM point eliminated if effective refractive index lies below physical limit (Max[sub or superstrate] + protected double wavelength = 0; // wavelength of the exciting light + protected boolean setWavelength= false; // = true when wavelength entered + protected double ko = 0.0D; // wave vector, 2pi/lambda + + protected double superstrateRefractiveIndex = 0.0D; // superstrate refractive index + // default value: air + protected double superstrateRefractiveIndex2 = 0.0D;// superstrate refractive index squared + protected double[] calcSuperstrateTEmodeRI = null; // calculated TE mode superstrate refractive index values + protected double[] calcSuperstrateTMmodeRI = null; // calculated TM mode superstrate refractive index values + protected double meanTEmodeSuperstrateRefractiveIndex = Double.NaN; // mean of the TE mode superstrate refractive indices + protected double meanTMmodeSuperstrateRefractiveIndex = Double.NaN; // mean of the TM mode superstrate refractive indices + + protected double sdTEmodeSuperstrateRefractiveIndex = Double.NaN; // standard deviation of the TE mode superstrate refractive indices + protected double sdTMmodeSuperstrateRefractiveIndex = Double.NaN; // standard deviation of the TM mode superstrate refractive indices + protected double sdSuperstrateRefractiveIndex = Double.NaN; // standard deviation of the superstrate refractive indices + protected boolean setSuperstrate = false; // = true when superstrate refractive index entered + protected boolean superCalculationDone = false; // = true when superstrate refractive index has been calculated + + protected double substrateRefractiveIndex = 0.0D; // substrate refractive index + protected double substrateRefractiveIndex2 = 0.0D; // substrate refractive index squared + protected boolean setSubstrate = false; // = true when substrate refractive index entered + protected double coreFilmRefractiveIndex = 0.0D; // guiding layer thin film refractive index + protected double coreFilmRefractiveIndex2 = 0.0D; // guiding layer thin film refractive index squared + protected boolean setCore = false; // = true when guiding layer refractive index entered or calculated + protected double[] coreFilmTEmodeRefractiveIndices = null; // core film TE mode refractive indices + protected double[] coreFilmTMmodeRefractiveIndices = null; // core film TM mode refractive indices + protected double meanTEmodeCoreFilmRefractiveIndex = Double.NaN; // mean of the TE mode core film refractive indices + protected double meanTMmodeCoreFilmRefractiveIndex = Double.NaN; // mean of the TM mode core film refractive indices + protected double meanCoreFilmRefractiveIndex = Double.NaN; // mean of the TE and TM mode core film refractive indices + protected double meanCoreFilmRefractiveIndex2 = Double.NaN; // square of the mean of the TE and TM mode core film refractive indices + protected double sdTEmodeCoreFilmRefractiveIndex = Double.NaN; // standard deviation of the TE mode core film refractive indices + protected double sdTMmodeCoreFilmRefractiveIndex = Double.NaN; // standard deviation of the TM mode core film refractive indices + protected double sdCoreFilmRefractiveIndex = Double.NaN; // standard deviation of the TE and TM mode core film refractive indices + protected double lowerBound = 0.0D; // lower bound in a root search + protected double upperBound = 0.0D; // upper bound in a root search + protected double tolerance = 1e-9; // root search tolerance + protected boolean calculationDone = false; // = true when calculation of core film refractive index/indices completed + + protected double prismToWaveguideGap = Double.POSITIVE_INFINITY; // prism to waveguide gap (subclass PrismCoupler) + protected boolean setPrismToWaveguideGap = false; // = true when prism to waveguide gap set (subclass PrismCoupler) + protected boolean fixedPrismToWaveguideGap = true; // = true when prism to waveguide gap set at a fixed value (subclass PrismCoupler) + // = false when prism to waveguide gap is to be estimated (subclass PrismCoupler) + protected double prismRefractiveIndex = 0.0D; // substrate refractive index + protected double prismRefractiveIndex2 = 0.0D; // substrate refractive index squared + + + // CONSTRUCTOR + public PlanarWaveguide(){ + } + + // THICKNESS (metres), EFFECTIVE REFRACTIVE INDEX AND MODE NUMBER DATA + // Enter TE mode data for a single measurement with no weights + public void enterTEmodeData(double thickness, double effectiveRI, double modeNumber){ + if(setMeasurementsTE){ + if(setErrorsTE)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTEmeasurements + 1; + double[][] hold = new double[nNew][4]; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + for(int j=0; j<4; j++)hold[i][j] = this.measurementsTE[i][j]; + } + hold[this.numberOfTEmeasurements][0] = thickness; + hold[this.numberOfTEmeasurements][1] = effectiveRI; + hold[this.numberOfTEmeasurements][2] = 1.0D; + hold[this.numberOfTEmeasurements][3] = modeNumber; + this.measurementsTE = hold; + this.numberOfTEmeasurements = nNew; + } + else{ + this.measurementsTE = new double[1][4]; + this.measurementsTE[0][0] = thickness; + this.measurementsTE[0][1] = effectiveRI; + this.measurementsTE[0][2] = 1.0D; + this.measurementsTE[0][3] = modeNumber; + this.numberOfTEmeasurements = 1; + } + this.numberOfMeasurements = this.numberOfTEmeasurements + this.numberOfTMmeasurements; + this.setMeasurementsTE = true; + this.setMeasurements = true; + } + + // Enter TE mode data for a single measurement with weights + public void enterTEmodeData(double thickness, double effectiveRI, double weight, double modeNumber){ + if(setMeasurementsTE){ + if(!setErrorsTE)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTEmeasurements + 1; + double[][] hold = new double[nNew][4]; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + for(int j=0; j<4; j++)hold[i][j] = this.measurementsTE[i][j]; + } + hold[this.numberOfTEmeasurements][0] = thickness; + hold[this.numberOfTEmeasurements][1] = effectiveRI; + hold[this.numberOfTEmeasurements][2] = weight; + hold[this.numberOfTEmeasurements][3] = modeNumber; + this.measurementsTE = hold; + this.numberOfTEmeasurements = nNew; + } + else{ + this.measurementsTE = new double[1][4]; + this.measurementsTE[0][0] = thickness; + this.measurementsTE[0][1] = effectiveRI; + this.measurementsTE[0][2] = weight; + this.measurementsTE[0][3] = modeNumber; + this.numberOfTEmeasurements = 1; + } + this.numberOfMeasurements = this.numberOfTEmeasurements + this.numberOfTMmeasurements; + this.setMeasurementsTE = true; + this.setMeasurements = true; + this.setErrorsTE = true; + } + + // Enter TE mode data for a range of measurements with no weights + public void enterTEmodeData(double[]thicknesses, double[] effectiveRIs, double[] modeNumbers){ + int o = thicknesses.length; + int n = effectiveRIs.length; + if(n!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of effective refractive indices, " + n); + int m = modeNumbers.length; + if(m!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of mode numbers, " + m); + + if(setMeasurementsTE){ + if(setErrorsTE)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTEmeasurements + o; + double[][] hold = new double[nNew][4]; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + for(int j=0; j<4; j++)hold[i][j] = this.measurementsTE[i][j]; + } + for(int i=0; i<o; i++){ + hold[this.numberOfTEmeasurements + i][0] = thicknesses[i]; + hold[this.numberOfTEmeasurements + i][1] = effectiveRIs[i]; + hold[this.numberOfTEmeasurements + i][2] = 1.0D; + hold[this.numberOfTEmeasurements + i][3] = modeNumbers[i]; + } + this.measurementsTE = hold; + this.numberOfTEmeasurements = nNew; + } + else{ + this.numberOfTEmeasurements = o; + this.measurementsTE = new double[this.numberOfTEmeasurements][4]; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + this.measurementsTE[i][0] = thicknesses[i]; + this.measurementsTE[i][1] = effectiveRIs[i]; + this.measurementsTE[i][2] = 1.0D; + this.measurementsTE[i][3] = modeNumbers[i]; + } + + } + this.numberOfMeasurements = this.numberOfTEmeasurements + this.numberOfTMmeasurements; + this.setMeasurementsTE = true; + this.setMeasurements = true; + } + + // Enter TE mode data for a range of measurements with weights + public void enterTEmodeData(double[]thicknesses, double[] effectiveRIs, double[] weights, double[] modeNumbers){ + int o = thicknesses.length; + int n = effectiveRIs.length; + if(n!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of effective refractive indices, " + n); + int m = modeNumbers.length; + if(m!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of mode numbers, " + m); + + if(setMeasurementsTE){ + if(!setErrorsTE)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTEmeasurements + o; + double[][] hold = new double[nNew][4]; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + for(int j=0; j<4; j++)hold[i][j] = this.measurementsTE[i][j]; + } + for(int i=0; i<o; i++){ + hold[this.numberOfTEmeasurements + i][0] = thicknesses[i]; + hold[this.numberOfTEmeasurements + i][1] = effectiveRIs[i]; + hold[this.numberOfTEmeasurements + i][2] = weights[i]; + hold[this.numberOfTEmeasurements + i][3] = modeNumbers[i]; + } + this.measurementsTE = hold; + this.numberOfTEmeasurements = nNew; + } + else{ + this.numberOfTEmeasurements = o; + this.measurementsTE = new double[this.numberOfTEmeasurements][4]; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + this.measurementsTE[i][0] = thicknesses[i]; + this.measurementsTE[i][1] = effectiveRIs[i]; + this.measurementsTE[i][2] = weights[i]; + this.measurementsTE[i][3] = modeNumbers[i]; + } + } + this.numberOfMeasurements = this.numberOfTEmeasurements + this.numberOfTMmeasurements; + this.setMeasurementsTE = true; + this.setMeasurements = true; + this.setErrorsTE = true; + } + + + + // Enter TM mode data for a single measurement with no weights + public void enterTMmodeData(double thickness, double effectiveRI, double modeNumber){ + if(setMeasurementsTM){ + if(setErrorsTM)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTMmeasurements + 1; + double[][] hold = new double[nNew][4]; + for(int i=0; i<this.numberOfTMmeasurements; i++){ + for(int j=0; j<4; j++)hold[i][j] = this.measurementsTM[i][j]; + } + hold[this.numberOfTMmeasurements][0] = thickness; + hold[this.numberOfTMmeasurements][1] = effectiveRI; + hold[this.numberOfTMmeasurements][2] = 1.0D; + hold[this.numberOfTMmeasurements][3] = modeNumber; + this.measurementsTM = hold; + this.numberOfTMmeasurements = nNew; + } + else{ + this.measurementsTM = new double[1][4]; + this.measurementsTM[0][0] = thickness; + this.measurementsTM[0][1] = effectiveRI; + this.measurementsTM[0][2] = 1.0D; + this.measurementsTM[0][3] = modeNumber; + this.numberOfTMmeasurements = 1; + } + this.numberOfMeasurements = this.numberOfTEmeasurements + this.numberOfTMmeasurements; + this.setMeasurementsTM = true; + this.setMeasurements = true; + } + + // Enter TM mode data for a single measurement with weights + public void enterTMmodeData(double thickness, double effectiveRI, double weight, double modeNumber){ + if(setMeasurementsTM){ + if(!setErrorsTM)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTMmeasurements + 1; + double[][] hold = new double[nNew][4]; + for(int i=0; i<this.numberOfTMmeasurements; i++){ + for(int j=0; j<4; j++)hold[i][j] = this.measurementsTM[i][j]; + } + hold[this.numberOfTMmeasurements][0] = thickness; + hold[this.numberOfTMmeasurements][1] = effectiveRI; + hold[this.numberOfTMmeasurements][2] = weight; + hold[this.numberOfTMmeasurements][3] = modeNumber; + this.measurementsTM = hold; + this.numberOfTMmeasurements = nNew; + } + else{ + this.measurementsTM = new double[1][4]; + this.measurementsTM[0][0] = thickness; + this.measurementsTM[0][1] = effectiveRI; + this.measurementsTM[0][2] = weight; + this.measurementsTM[0][3] = modeNumber; + this.numberOfTMmeasurements = 1; + } + this.numberOfMeasurements = this.numberOfTMmeasurements + this.numberOfTMmeasurements; + this.setMeasurementsTM = true; + this.setMeasurements = true; + this.setErrorsTM = true; + } + + // Enter TM mode data for a range of measurements without weights + public void enterTMmodeData(double[]thicknesses, double[] effectiveRIs, double[] modeNumbers){ + int o = thicknesses.length; + int n = effectiveRIs.length; + if(n!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of effective refractive indices, " + n); + int m = modeNumbers.length; + if(m!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of mode numbers, " + m); + + if(setMeasurementsTM){ + if(setErrorsTM)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTMmeasurements + o; + double[][] hold = new double[nNew][4]; + for(int i=0; i<this.numberOfTMmeasurements; i++){ + for(int j=0; j<4; j++)hold[i][j] = this.measurementsTM[i][j]; + } + for(int i=0; i<o; i++){ + hold[this.numberOfTMmeasurements + i][0] = thicknesses[i]; + hold[this.numberOfTMmeasurements + i][1] = effectiveRIs[i]; + hold[this.numberOfTMmeasurements + i][2] = 1.0D; + hold[this.numberOfTMmeasurements + i][3] = modeNumbers[i]; + } + this.measurementsTM = hold; + this.numberOfTMmeasurements = nNew; + } + else{ + this.numberOfTMmeasurements = o; + this.measurementsTM = new double[this.numberOfTMmeasurements][4]; + for(int i=0; i<this.numberOfTMmeasurements; i++){ + this.measurementsTM[i][0] = thicknesses[i]; + this.measurementsTM[i][1] = effectiveRIs[i]; + this.measurementsTM[i][2] = 1.0D; + this.measurementsTM[i][3] = modeNumbers[i]; + } + } + this.numberOfMeasurements = this.numberOfTMmeasurements + this.numberOfTMmeasurements; + this.setMeasurementsTM = true; + this.setMeasurements = true; + } + + // Enter TM mode data for a range of measurements with weights + public void enterTMmodeData(double[]thicknesses, double[] effectiveRIs, double[] weights, double[] modeNumbers){ + int o = thicknesses.length; + int n = effectiveRIs.length; + if(n!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of effective refractive indices, " + n); + int m = modeNumbers.length; + if(m!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of mode numbers, " + m); + + if(setMeasurementsTM){ + if(!setErrorsTM)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTMmeasurements + o; + double[][] hold = new double[nNew][4]; + for(int i=0; i<this.numberOfTMmeasurements; i++){ + for(int j=0; j<4; j++)hold[i][j] = this.measurementsTM[i][j]; + } + for(int i=0; i<o; i++){ + hold[this.numberOfTMmeasurements + i][0] = thicknesses[i]; + hold[this.numberOfTMmeasurements + i][1] = effectiveRIs[i]; + hold[this.numberOfTMmeasurements + i][2] = weights[i]; + hold[this.numberOfTMmeasurements + i][3] = modeNumbers[i]; + } + this.measurementsTM = hold; + this.numberOfTMmeasurements = nNew; + } + else{ + this.numberOfTMmeasurements = o; + this.measurementsTM = new double[this.numberOfTMmeasurements][4]; + for(int i=0; i<this.numberOfTMmeasurements; i++){ + this.measurementsTM[i][0] = thicknesses[i]; + this.measurementsTM[i][1] = effectiveRIs[i]; + this.measurementsTM[i][2] = weights[i]; + this.measurementsTM[i][3] = modeNumbers[i]; + } + } + this.numberOfMeasurements = this.numberOfTMmeasurements + this.numberOfTMmeasurements; + this.setMeasurementsTM = true; + this.setMeasurements = true; + this.setErrorsTM = true; + } + + // Clear entered thickness, effective refractive index and mode number data + // so new dat may be entered without it being appended to the existing data + public void clearData(){ + this.numberOfMeasurements = 0; + this.setMeasurements = false; + this.setWeights = false; + + this.numberOfTEmeasurements = 0; + this.setMeasurementsTE = false; + this.setErrorsTE = false; + + this.numberOfTMmeasurements = 0; + this.setMeasurementsTM = false; + this.setErrorsTM = false; + } + + // WAVELENGTH + // Enter the wavelength (metres) + public void setWavelength(double wavelength){ + this.wavelength = wavelength; + this.setWavelength = true; + this.ko = 2.0D*Math.PI/this.wavelength; + if(!this.setSuperstrate)this.superstrateRefractiveIndex = RefractiveIndex.air(this.wavelength); + } + + // SUBSTRATE REFRACTIVE INDEX + // Enter the substrate refractive index + public void setSubstrateRefractiveIndex(double refIndex){ + this.substrateRefractiveIndex = refIndex; + this.substrateRefractiveIndex2 = refIndex*refIndex; + this.setSubstrate= true; + } + + // SUPERSTRATE REFRACTIVE INDEX + // Enter the superstrate refractive index + public void setSuperstrateRefractiveIndex(double refIndex){ + this.superstrateRefractiveIndex = refIndex; + this.superstrateRefractiveIndex2 = refIndex*refIndex; + this.setSuperstrate = true; + } + + // RETURN SUPERSTRATE REFRACTIVE INDEX + // Return superstrate refractive index + public double getSuperstrateRefractiveIndex(){ + if(!this.superCalculationDone && this.setCore)this.calcSuperstrateRefractiveIndex(); + return this.superstrateRefractiveIndex; + } + + // Return standard deviation of the superstrate refractive index + public double getStandardDeviationSuperstrateRefractiveIndex(){ + if(!this.superCalculationDone && this.setCore)this.calcSuperstrateRefractiveIndex(); + if(this.setCore){ + if((this.numberOfTMmeasurements+this.numberOfTEmeasurements)==1)System.out.println("Method: getStandardDeviationSuperstrateRefractiveIndex - Only one measurement entered - NO standard deviation returned"); + } + else{ + System.out.println("Method: getStandardDeviationSuperstrateRefractiveIndex - Superstrate refractive index was entered and NOT calculated - NO standard deviation returned"); + } + return this.sdCoreFilmRefractiveIndex; + } + + // CORE FILM REFRACTIVE INDEX + // Enter the core film refractive index + public void setCoreLayerRefractiveIndex(double refIndex){ + this.coreFilmRefractiveIndex = refIndex; + this.coreFilmRefractiveIndex2 = refIndex*refIndex; + this.setCore = true; + } + + // RETURN CORE FILM REFRACTIVE INDICES + // Return TE mode core film refractive indices + public double[] getTEmodeCoreFilmRefractiveIndices(){ + if(!this.calculationDone)this.calcCoreFilmRefractiveIndices(); + if(this.numberOfTEmeasurements==0)System.out.println("Method: getTEmodeCoreFilmRefractiveIndices - NO TE mode data entered - NO refractive indices returned"); + return this.coreFilmTEmodeRefractiveIndices; + } + + // Return TM mode core film refractive indices + public double[] getTMmodeCoreFilmRefractiveIndices(){ + if(!this.calculationDone)this.calcCoreFilmRefractiveIndices(); + if(this.numberOfTMmeasurements==0)System.out.println("Method: getTMmodeCoreFilmRefractiveIndices - NO TM mode data entered - NO refractive indices returned"); + return this.coreFilmTMmodeRefractiveIndices; + } + + // Return TE mode average core film refractive index + public double getMeanTEmodeCoreFilmRefractiveIndex(){ + if(!this.calculationDone)this.calcCoreFilmRefractiveIndices(); + if(this.numberOfTEmeasurements==0)System.out.println("Method: getMeanTEmodeCoreFilmRefractiveIndices - NO TE mode data entered - NO refractive index returned"); + return this.meanTEmodeCoreFilmRefractiveIndex; + } + + // Return TM mode average core film refractive index + public double getMeanTMmodeCoreFilmRefractiveIndex(){ + if(!this.calculationDone)this.calcCoreFilmRefractiveIndices(); + if(this.numberOfTMmeasurements==0)System.out.println("Method: getMeanTMmodeCoreFilmRefractiveIndices - NO TM mode data entered - NO refractive index returned"); + return this.meanTMmodeCoreFilmRefractiveIndex; + } + + // Return overall average core film refractive index + public double getMeanCoreFilmRefractiveIndex(){ + if(!this.calculationDone)this.calcCoreFilmRefractiveIndices(); + return this.meanCoreFilmRefractiveIndex; + } + + // Return core film refractive index + public double getCoreFilmRefractiveIndex(){ + if(!this.calculationDone && !this.setCore)this.calcCoreFilmRefractiveIndices(); + return this.coreFilmRefractiveIndex; + } + + // Return standard deviation of the core film TE mode refractive index + public double getStandardDeviationTEmodeCoreFilmRefractiveIndex(){ + if(!this.calculationDone)this.calcCoreFilmRefractiveIndices(); + if(this.numberOfTEmeasurements==0)System.out.println("Method: getStandardDeviationTEmodeCoreFilmRefractiveIndex - NO TE mode data entered - NO standard deviation returned"); + if(this.numberOfTEmeasurements==1)System.out.println("Method: getStandardDeviationTEmodeCoreFilmRefractiveIndex - Only one measurement entered - NO standard deviation returned"); + return this.sdTEmodeCoreFilmRefractiveIndex; + } + + // Return standard deviation of the core film TM mode refractive index + public double getStandardDeviationTMmodeCoreFilmRefractiveIndex(){ + if(!this.calculationDone)this.calcCoreFilmRefractiveIndices(); + if(this.numberOfTMmeasurements==0)System.out.println("Method: getStandardDeviationTMmodeCoreFilmRefractiveIndex - NO TM mode data entered - NO standard deviation returned"); + if(this.numberOfTMmeasurements==1)System.out.println("Method: getStandardDeviationTMmodeCoreFilmRefractiveIndex - Only one measurement entered - NO standard deviation returned"); + return this.sdTMmodeCoreFilmRefractiveIndex; + } + + // Return standard deviation of the overall core film refractive index + public double getStandardDeviationCoreFilmRefractiveIndex(){ + if(!this.calculationDone)this.calcCoreFilmRefractiveIndices(); + if((this.numberOfTMmeasurements+this.numberOfTEmeasurements)==1)System.out.println("Method: getStandardDeviationCoreFilmRefractiveIndex - Only one measurement entered - NO standard deviation returned"); + return this.sdCoreFilmRefractiveIndex; + } + + // EFFECTIVE REFRACTIVE INDICES + // Return experimental TE mode effective refractive indices + public double[][] getTEmodeExperimentalEffectiveRefractiveIndices(){ + double[][] returnedArray = null; + if(this.numberOfTEmeasurements==0){ + System.out.println("Method: getTEmodeExperimentalEffectiveRefractiveIndices - NO TE mode data entered - NO effective refractive indices returned"); + } + else{ + returnedArray = new double[2][this.numberOfTEmeasurements]; + returnedArray[0] = this.thicknessesUsedTE; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + returnedArray[1][i] = this.measurementsTE[i][1]; + } + } + return returnedArray; + } + + // Return errors in the experimental TE mode effective refractive indices + public double[][] getTEmodeEffectiveRefractiveIndicesErrors(){ + double[][] returnedArray = null; + if(this.numberOfTEmeasurements==0){ + System.out.println("Method: getTEmodeExperimentalEffectiveRefractiveIndices - NO TE mode data entered - NO errors returned"); + } + else{ + if(!this.setErrorsTE){ + System.out.println("Method: getTEmodeExperimentalEffectiveRefractiveIndices - NO TE mode errors entered - NO errors returned"); + } + else{ + returnedArray = new double[2][this.numberOfTEmeasurements]; + returnedArray[0] = this.thicknessesUsedTE; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + returnedArray[1][i] = this.measurementsTE[i][2]; + } + } + } + return returnedArray; + } + + // Return experimental TM mode effective refractive indices + public double[][] getTMmodeExperimentalEffectiveRefractiveIndices(){ + double[][] returnedArray = null; + if(this.numberOfTMmeasurements==0){ + System.out.println("Method: getTMmodeExperimentalEffectiveRefractiveIndices - NO TM mode data entered - NO effective refractive indices returned"); + } + else{ + returnedArray = new double[2][this.numberOfTMmeasurements]; + returnedArray[0] = this.thicknessesUsedTM; + for(int i=0; i<this.numberOfTMmeasurements; i++){ + returnedArray[1][i] = this.measurementsTM[i][1]; + } + } + return returnedArray; + } + + // Return errors in the experimental TM mode effective refractive indices + public double[][] getTMmodeEffectiveRefractiveIndicesErrors(){ + double[][] returnedArray = null; + if(this.numberOfTMmeasurements==0){ + System.out.println("Method: getTMmodeExperimentalEffectiveRefractiveIndices - NO TM mode data entered - NO errors returned"); + } + else{ + if(!this.setErrorsTM){ + System.out.println("Method: getTMmodeExperimentalEffectiveRefractiveIndices - NO TM mode errors entered - NO errors returned"); + } + else{ + returnedArray = new double[2][this.numberOfTMmeasurements]; + returnedArray[0] = this.thicknessesUsedTM; + for(int i=0; i<this.numberOfTMmeasurements; i++){ + returnedArray[1][i] = this.measurementsTM[i][2]; + } + } + } + return returnedArray; + } + + // Return calculated TE mode effective refractive indices for the calculated mean core refractive index + public double[][] getTEmodeCalculatedEffectiveRefractiveIndices(){ + if(!this.calculationDone)this.calcCoreFilmRefractiveIndices(); + if(this.numberOfTEmeasurements==0)System.out.println("Method: getStandardDeviationTEmodeCoreFilmRefractiveIndices - NO TE mode data entered - NO effective refractive indices returned"); + double[][] returnedArray = new double[2][this.numberOfTEmeasurements]; + + // Create instance of the class holding the TE mode effective refractive index function + FunctTEplot func = new FunctTEplot(); + + // Set function parameters + func.substrateRefractiveIndex2 = this.substrateRefractiveIndex2; + func.superstrateRefractiveIndex2 = this.superstrateRefractiveIndex2; + func.coreFilmRefractiveIndex2 = this.coreFilmRefractiveIndex2; + func.prismRefractiveIndex2 = this.prismRefractiveIndex2; + func.prismToWaveguideGap = this.prismToWaveguideGap; + func.setPrismToWaveguideGap = this.setPrismToWaveguideGap; + func.ko = this.ko; + + this.lowerBound = Math.max(this.substrateRefractiveIndex, this.superstrateRefractiveIndex); + this.upperBound = Math.min(this.coreFilmRefractiveIndex, this.prismRefractiveIndex); + + for(int i=0; i<this.numberOfTEmeasurements; i++){ + + // set further function parameter + func.thickness = this.measurementsTE[i][0]; + func.modeNumber = this.measurementsTE[i][3]; + + // call root searching method, bisection + RealRoot rr = new RealRoot(); + rr.noBoundsExtensions(); + rr.setTolerance(this.tolerance); + this.calcEffectRefrIndicesTE[i] = rr.bisect(func, this.lowerBound, this.upperBound); + } + returnedArray[0] = this.thicknessesUsedTE; + returnedArray[1] = this.calcEffectRefrIndicesTE; + + return returnedArray; + } + + // Return calculated TM mode effective refractive indices for the calculated mean core refractive index + public double[][] getTMmodeCalculatedEffectiveRefractiveIndices(){ + if(!this.calculationDone)this.calcCoreFilmRefractiveIndices(); + if(this.numberOfTMmeasurements==0)System.out.println("Method: getStandardDeviationTMmodeCoreFilmRefractiveIndices - NO TM mode data entered - NO effective refractive indices returned"); + double[][] returnedArray = new double[2][this.numberOfTMmeasurements]; + + // Create instance of the class holding the TM mode effective refractive index function + FunctTMplot func = new FunctTMplot(); + + // Set function parameters + func.substrateRefractiveIndex2 = this.substrateRefractiveIndex2; + func.superstrateRefractiveIndex2 = this.superstrateRefractiveIndex2; + func.coreFilmRefractiveIndex2 = this.coreFilmRefractiveIndex2; + func.prismRefractiveIndex2 = this.prismRefractiveIndex2; + func.prismToWaveguideGap = this.prismToWaveguideGap; + func.setPrismToWaveguideGap = this.setPrismToWaveguideGap; + func.ko = this.ko; + + this.lowerBound = Math.max(this.substrateRefractiveIndex, this.superstrateRefractiveIndex); + this.upperBound = Math.min(this.coreFilmRefractiveIndex, this.prismRefractiveIndex); + + for(int i=0; i<this.numberOfTMmeasurements; i++){ + + // set further function parameter + func.thickness = this.measurementsTM[i][0]; + func.modeNumber = this.measurementsTM[i][3]; + + // call root searching method, bisection + RealRoot rr = new RealRoot(); + rr.noBoundsExtensions(); + rr.setTolerance(this.tolerance); + this.calcEffectRefrIndicesTM[i] = rr.bisect(func, this.lowerBound, this.upperBound); + } + returnedArray[0] = this.thicknessesUsedTM; + returnedArray[1] = this.calcEffectRefrIndicesTM; + + return returnedArray; + } + + // CALCULATION OF THE GUIDING CORE FILM REFRACTIVE INDEX/INDICES + public void calcCoreFilmRefractiveIndices(){ + if(!this.setMeasurements)throw new IllegalArgumentException("Either no thickness, angle/effective refractive index, mode number data has been entered or a key subclass variable, e.g. coupling prism corner angle has not been entered"); + if(!this.setWavelength)throw new IllegalArgumentException("No wavelength has been entered"); + if(!this.setSubstrate)throw new IllegalArgumentException("No substrate refractive index has been entered"); + + // Set the bounds and eliminate points where effective ref. index < substrate or superstrate ref. index + this.lowerBound = Math.max(this.substrateRefractiveIndex, this.superstrateRefractiveIndex); + this.upperBound = 0.0D; + + if(this.numberOfTEmeasurements>0)this.eliminatedTE = new boolean[this.numberOfTEmeasurements]; + int elimNumberTE = 0; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + this.eliminatedTE[i] = false; + if(this.measurementsTE[i][1]<this.lowerBound){ + System.out.println("TE mode measurement point, " + i + ", eliminated as the effective refractive index, " + this.measurementsTE[i][1] + ", lies below the physical limit, " + this.lowerBound); + this.eliminatedTE[i] = true; + elimNumberTE++; + } + else{ + if(this.upperBound<this.measurementsTE[i][1])this.upperBound = this.measurementsTE[i][1]; + } + } + if(elimNumberTE>0){ + int newNumber = this.numberOfTEmeasurements - elimNumberTE; + if(newNumber==0){ + this.numberOfTEmeasurements = 0; + } + else{ + double[][] temp = new double[newNumber][3]; + int nIndex = 0; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + if(!this.eliminatedTE[i]){ + temp[nIndex][0] = this.measurementsTE[i][0]; + temp[nIndex][1] = this.measurementsTE[i][1]; + temp[nIndex][2] = this.measurementsTE[i][2]; + temp[nIndex][3] = this.measurementsTE[i][3]; + nIndex++; + } + } + this.measurementsTE = temp; + this.numberOfTEmeasurements = newNumber; + this.numberOfMeasurements = this.numberOfTEmeasurements + this.numberOfTMmeasurements; + } + } + this.thicknessesUsedTE = new double[this.numberOfTEmeasurements]; + this.calcEffectRefrIndicesTE = new double[this.numberOfTEmeasurements]; + for(int i=0; i<this.numberOfTEmeasurements; i++)this.thicknessesUsedTE[i] = this.measurementsTE[i][0]; + this.maximumTEmodeEffectiveRefractiveIndex = this.upperBound; + + this.upperBound = 0.0D; + if(this.numberOfTMmeasurements>0)this.eliminatedTM = new boolean[this.numberOfTMmeasurements]; + int elimNumberTM = 0; + for(int i=0; i<this.numberOfTMmeasurements; i++){ + this.eliminatedTM[i] = false; + if(this.measurementsTM[i][1]<this.lowerBound){ + System.out.println("TM mode measurement point, " + i + ", eliminated as the effective refractive index, " + this.measurementsTM[i][1] + ", lies below the physical limit, " + this.lowerBound); + this.eliminatedTM[i] = true; + elimNumberTM++; + } + else{ + if(this.upperBound<this.measurementsTM[i][1])this.upperBound = this.measurementsTM[i][1]; + } + } + if(elimNumberTM>0){ + int newNumber = this.numberOfTMmeasurements - elimNumberTM; + if(newNumber==0){ + this.numberOfTMmeasurements = 0; + } + else{ + double[][] temp = new double[newNumber][3]; + int nIndex = 0; + for(int i=0; i<this.numberOfTMmeasurements; i++){ + if(!this.eliminatedTM[i]){ + temp[nIndex][0] = this.measurementsTM[i][0]; + temp[nIndex][1] = this.measurementsTM[i][1]; + temp[nIndex][2] = this.measurementsTM[i][2]; + temp[nIndex][3] = this.measurementsTM[i][3]; + nIndex++; + } + } + this.measurementsTM = temp; + this.numberOfTMmeasurements = newNumber; + this.numberOfMeasurements = this.numberOfTEmeasurements + this.numberOfTMmeasurements; + } + } + this.thicknessesUsedTM = new double[this.numberOfTMmeasurements]; + this.calcEffectRefrIndicesTM = new double[this.numberOfTMmeasurements]; + for(int i=0; i<this.numberOfTMmeasurements; i++)this.thicknessesUsedTM[i] = this.measurementsTM[i][0]; + this.maximumTMmodeEffectiveRefractiveIndex = this.upperBound; + + if(this.numberOfMeasurements==0)throw new IllegalArgumentException("All data points rejected as lying outside the physically meaningful bounds"); + + if(this.fixedPrismToWaveguideGap){ + this.calcCoreFilmRefractiveIndicesFixedGap(); + } + else{ + this.calcCoreFilmRefractiveIndicesEstimatedGap(); + } + } + + // Calculates core refractive index and the prism to waveguide gap + public void calcCoreFilmRefractiveIndicesEstimatedGap(){ + + // ArrayList to store sum of squares on each gap distance decrement + ArrayList<Double> arrayl = new ArrayList<Double>(); + + // initial gap distance + this.prismToWaveguideGap = 1.e1; + + // set calculation to fixed gap for each gap decrement calculation + this.fixedPrismToWaveguideGap = true; + + // arrays to store experimental and, at each gap decrement, the calculated effective refractive indices + double[] effectExpl = new double[this.numberOfMeasurements]; + double[] effectCalc = new double[this.numberOfMeasurements]; + + // Collect experimental effective refractive indices + for(int i=0; i<this.numberOfTEmeasurements; i++)effectExpl[i] = this.measurementsTE[i][1]; + for(int i=0; i<this.numberOfTMmeasurements; i++)effectExpl[i + this.numberOfTEmeasurements] = this.measurementsTM[i][1]; + + // Sum of squares of experimental - calculated effective refractive indices at each gap decrement + double sumOfSquares = 0.0D; + + // Sum of squares at preceding gap decrement + double sumOfSquaresLast = Double.POSITIVE_INFINITY; + + // Number of decrements + int numberOfDecrements = 0; + + // Decrementing loop in which sum of squares calculted + boolean test = true; + while(test){ + + // Set flags to allow new calculation of core refractive index + this.setCore = false; + this.calculationDone = false; + this.fixedPrismToWaveguideGap = true; + this.setPrismToWaveguideGap=true; + + // Get mean core refractive index at current gap value + double coreRI = this.getMeanCoreFilmRefractiveIndex(); + + // Check whether physically meaningful root found + if(coreRI!=coreRI){ + System.out.println("NaN"); + test = false; + } + else{ + // Calculate sum of squares + double[][] effectTECalc = this.getTEmodeCalculatedEffectiveRefractiveIndices(); + for(int i=0; i<this.numberOfTEmeasurements; i++)effectCalc[i] = effectTECalc[1][i]; + double[][] effectTMCalc = this.getTMmodeCalculatedEffectiveRefractiveIndices(); + for(int i=0; i<this.numberOfTMmeasurements; i++)effectCalc[i + this.numberOfTEmeasurements] = effectTMCalc[1][i]; + sumOfSquares = 0.0D; + for(int i=0; i<this.numberOfMeasurements; i++)sumOfSquares += Fmath.square(effectExpl[i] - effectCalc[i]); + + // store values + System.out.println(this.prismToWaveguideGap + " " + coreRI + " " + sumOfSquares); + arrayl.add(new Double(coreRI)); + arrayl.add(new Double(sumOfSquares)); + numberOfDecrements++; + + // Decrement gap distance and check for termination gap distance + this.prismToWaveguideGap /= 2.0; + if(this.prismToWaveguideGap<1.0e-10)test = false; + } + } + } + + + // Calculates core refractive index for either fixed prism to waveguide gap or on ignoring prism perturbation + public void calcCoreFilmRefractiveIndicesFixedGap(){ + // call the root search methods to obtain the core refractive index/indices + if(this.numberOfTEmeasurements>0)this.calcTEmodeCoreFilmRefractiveIndices(); + if(this.numberOfTMmeasurements>0)this.calcTMmodeCoreFilmRefractiveIndices(); + + // Calculate the overall mean and standard deviation of the core refractive indices + if(this.numberOfTEmeasurements>0 && this.numberOfTMmeasurements==0){ + this.meanCoreFilmRefractiveIndex = this.meanTEmodeCoreFilmRefractiveIndex; + this.coreFilmRefractiveIndex = this.meanCoreFilmRefractiveIndex; + this.sdCoreFilmRefractiveIndex = this.sdTEmodeCoreFilmRefractiveIndex; + } + else{ + if(this.numberOfTMmeasurements>0 && this.numberOfTEmeasurements==0){ + this.meanCoreFilmRefractiveIndex = this.meanTMmodeCoreFilmRefractiveIndex; + this.coreFilmRefractiveIndex = this.meanCoreFilmRefractiveIndex; + this.sdCoreFilmRefractiveIndex = this.sdTMmodeCoreFilmRefractiveIndex; + } + else{ + double[] values = new double[this.numberOfMeasurements]; + double[] weights = new double[this.numberOfMeasurements]; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + values[i] = this.coreFilmTEmodeRefractiveIndices[i]; + weights[i] = this.measurementsTE[i][2]; + } + for(int i=0; i<this.numberOfTMmeasurements; i++){ + values[i+this.numberOfTEmeasurements] = this.coreFilmTMmodeRefractiveIndices[i]; + weights[i+this.numberOfTEmeasurements] = this.measurementsTM[i][2]; + } + this.meanCoreFilmRefractiveIndex = Stat.mean(values, weights); + this.sdCoreFilmRefractiveIndex = Stat.standardDeviation(values, weights); + this.coreFilmRefractiveIndex = this.meanCoreFilmRefractiveIndex; + } + } + + this.meanCoreFilmRefractiveIndex2 = this.meanCoreFilmRefractiveIndex*this.meanCoreFilmRefractiveIndex; + this.coreFilmRefractiveIndex2 = this.meanCoreFilmRefractiveIndex2; + this.maximumEffectiveRefractiveIndex = Math.max(this.maximumTEmodeEffectiveRefractiveIndex, this.maximumTMmodeEffectiveRefractiveIndex); + this.setCore = true; + this.calculationDone = true; + } + + // Calculate TE mode refractive indices + public void calcTEmodeCoreFilmRefractiveIndices(){ + + this.coreFilmTEmodeRefractiveIndices = new double[this.numberOfTEmeasurements]; + + // Create instance of the class holding the TE mode core film refractive indexfunction + FunctTE func = new FunctTE(); + + // Set function parameters + func.substrateRefractiveIndex2 = this.substrateRefractiveIndex2; + func.superstrateRefractiveIndex2 = this.superstrateRefractiveIndex2; + func.prismRefractiveIndex2 = this.prismRefractiveIndex2; + func.prismToWaveguideGap = this.prismToWaveguideGap; + func.setPrismToWaveguideGap = this.setPrismToWaveguideGap; + func.ko = this.ko; + + double[] weights = new double[this.numberOfTEmeasurements]; + this.lowerBound = this.maximumTEmodeEffectiveRefractiveIndex; + this.upperBound = 2.0D*this.lowerBound; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + weights[i] = this.measurementsTE[i][2]; + + // set further function parameters + func.thickness = this.measurementsTE[i][0]; + func.effectiveRefractiveIndex2 = this.measurementsTE[i][1]*this.measurementsTE[i][1]; + func.modeNumber = this.measurementsTE[i][3]; + + // call root searching method, bisection, to obtain core refractive index + RealRoot rr = new RealRoot(); + rr.noLowerBoundExtension(); + rr.setTolerance(this.tolerance); + this.coreFilmTEmodeRefractiveIndices[i] = rr.bisect(func, this.lowerBound, this.upperBound); + } + + // Calculate mean and sd + if(this.numberOfTEmeasurements>1){ + this.meanTEmodeCoreFilmRefractiveIndex = Stat.mean(this.coreFilmTEmodeRefractiveIndices, weights); + this.sdTEmodeCoreFilmRefractiveIndex = Stat.standardDeviation(this.coreFilmTEmodeRefractiveIndices, weights); + } + else{ + this.meanTEmodeCoreFilmRefractiveIndex = this.coreFilmTEmodeRefractiveIndices[0]; + } + } + + // Calculate TM mode refractive indices + public void calcTMmodeCoreFilmRefractiveIndices(){ + + this.coreFilmTMmodeRefractiveIndices = new double[this.numberOfTMmeasurements]; + + // Create instance of the class holding the TE mode core film refractive index function + FunctTM func = new FunctTM(); + + // Set function parameters + func.substrateRefractiveIndex2 = this.substrateRefractiveIndex2; + func.superstrateRefractiveIndex2 = this.superstrateRefractiveIndex2; + func.prismRefractiveIndex2 = this.prismRefractiveIndex2; + func.prismToWaveguideGap = this.prismToWaveguideGap; + func.setPrismToWaveguideGap = this.setPrismToWaveguideGap; + func.ko = this.ko; + + double[] weights = new double[this.numberOfTMmeasurements]; + this.lowerBound = this.maximumTMmodeEffectiveRefractiveIndex; + this.upperBound = 2.0D*this.lowerBound; + for(int i=0; i<this.numberOfTMmeasurements; i++){ + weights[i] = this.measurementsTM[i][2]; + + // set further function parameters + func.thickness = this.measurementsTM[i][0]; + func.effectiveRefractiveIndex2 = this.measurementsTM[i][1]*this.measurementsTM[i][1]; + func.modeNumber = this.measurementsTM[i][3]; + + // call root searching method, bisection, to obtain core refractive index + RealRoot rr = new RealRoot(); + rr.noLowerBoundExtension(); + rr.setTolerance(this.tolerance); + this.coreFilmTMmodeRefractiveIndices[i] = rr.bisect(func, this.lowerBound, this.upperBound); + } + + // Calculate mean and sd + if(this.numberOfTMmeasurements>1){ + this.meanTMmodeCoreFilmRefractiveIndex = Stat.mean(this.coreFilmTMmodeRefractiveIndices, weights); + this.sdTMmodeCoreFilmRefractiveIndex = Stat.standardDeviation(this.coreFilmTMmodeRefractiveIndices, weights); + } + else{ + this.meanTMmodeCoreFilmRefractiveIndex = this.coreFilmTMmodeRefractiveIndices[0]; + } + } + + // Calculate a TE mode dispersion curve + public double[][] dispersionCurveTE(double lowThickness, double highThickness, int numberOfPoints, double modeNumber){ + if(!this.setWavelength)throw new IllegalArgumentException("No wavelength has been entered"); + if(!this.setSubstrate)throw new IllegalArgumentException("No substrate refractive index has been entered"); + if(!this.setCore)throw new IllegalArgumentException("No core film refractive index has been calculated or entered"); + + // Create arrays + double[] thickness = new double[numberOfPoints]; + double[] effective = new double[numberOfPoints]; + double[][] returnedArray = new double[2][numberOfPoints]; + double incr = (Fmath.log10(highThickness) - Fmath.log10(lowThickness))/(numberOfPoints - 1); + thickness[0] = Fmath.log10(lowThickness); + thickness[numberOfPoints-1] = Fmath.log10(highThickness); + for(int i=1; i<numberOfPoints-1; i++)thickness[i] = thickness[i-1] + incr; + returnedArray[0] = thickness; + + // Create instance of the class holding the TE mode effective refractive index function + FunctTEplot func = new FunctTEplot(); + + // Set function parameters + func.substrateRefractiveIndex2 = this.substrateRefractiveIndex2; + func.superstrateRefractiveIndex2 = this.superstrateRefractiveIndex2; + func.coreFilmRefractiveIndex2 = this.coreFilmRefractiveIndex2; + func.prismRefractiveIndex2 = this.prismRefractiveIndex2; + func.prismToWaveguideGap = this.prismToWaveguideGap; + func.setPrismToWaveguideGap = this.setPrismToWaveguideGap; + func.ko = this.ko; + func.modeNumber = modeNumber; + + this.lowerBound = Math.max(this.substrateRefractiveIndex, this.superstrateRefractiveIndex); + this.upperBound = Math.min(this.coreFilmRefractiveIndex, this.prismRefractiveIndex); + + for(int i=0; i<numberOfPoints; i++){ + // set further function parameter + func.thickness = Math.pow(10.0D, thickness[i]); + + // call root searching method, bisection + RealRoot rr = new RealRoot(); + rr.noBoundsExtensions(); + rr.setTolerance(this.tolerance); + effective[i] = rr.bisect(func, this.lowerBound, this.upperBound); + } + returnedArray[1] = effective; + return returnedArray; + } + + // Calculate a TM mode dispersion curve + public double[][] dispersionCurveTM(double lowThickness, double highThickness, int numberOfPoints, double modeNumber){ + if(!this.setWavelength)throw new IllegalArgumentException("No wavelength has been entered"); + if(!this.setSubstrate)throw new IllegalArgumentException("No substrate refractive index has been entered"); + if(!this.setCore)throw new IllegalArgumentException("No core film refractive index has been calculated or entered"); + + // Create arrays + double[] thickness = new double[numberOfPoints]; + double[] effective = new double[numberOfPoints]; + double[][] returnedArray = new double[2][numberOfPoints]; + double incr = (Fmath.log10(highThickness) - Fmath.log10(lowThickness))/(numberOfPoints - 1); + thickness[0] = Fmath.log10(lowThickness); + thickness[numberOfPoints-1] = Fmath.log10(highThickness); + for(int i=1; i<numberOfPoints-1; i++)thickness[i] = thickness[i-1] + incr; + returnedArray[0] = thickness; + + // Create instance of the class holding the TM mode effective refractive index function + FunctTMplot func = new FunctTMplot(); + + // Set function parameters + func.substrateRefractiveIndex2 = this.substrateRefractiveIndex2; + func.superstrateRefractiveIndex2 = this.superstrateRefractiveIndex2; + func.coreFilmRefractiveIndex2 = this.coreFilmRefractiveIndex2; + func.prismRefractiveIndex2 = this.prismRefractiveIndex2; + func.prismToWaveguideGap = this.prismToWaveguideGap; + func.setPrismToWaveguideGap = this.setPrismToWaveguideGap; + func.ko = this.ko; + func.modeNumber = modeNumber; + + this.lowerBound = Math.max(this.substrateRefractiveIndex, this.superstrateRefractiveIndex); + this.upperBound = Math.min(this.coreFilmRefractiveIndex, this.prismRefractiveIndex); + for(int i=0; i<numberOfPoints; i++){ + // set further function parameter + func.thickness = Math.pow(10.0D, thickness[i]); + + // call root searching method, bisection + RealRoot rr = new RealRoot(); + rr.noBoundsExtensions(); + rr.setTolerance(this.tolerance); + effective[i] = rr.bisect(func, this.lowerBound, this.upperBound); + } + returnedArray[1] = effective; + return returnedArray; + } + + // Calculate and plot a TE dispersion curve + // Graph title not provided + public double[][] plotDispersionCurveTE(double lowThickness, double highThickness, int numberOfPoints, double modeNumber){ + String legend1 = " "; + return this.plotDispersionCurveTE(lowThickness, highThickness, numberOfPoints, modeNumber, legend1); + } + + // Calculate and plot a TE dispersion curve + // Graph title provided + public double[][] plotDispersionCurveTE(double lowThickness, double highThickness, int numberOfPoints, double modeNumber, String legend1){ + + //Calculate curve + double[][] curve = dispersionCurveTE(lowThickness, highThickness, numberOfPoints, modeNumber); + + // Create instance of PlotGraph + PlotGraph pg1 = new PlotGraph(curve); + int lineOption = 3; + if(numberOfPoints<100)lineOption = 1; + pg1.setLine(lineOption); + pg1.setPoint(0); + String legend0 = "Dispersion curve: TE mode - mode number " + (int)modeNumber; + pg1.setGraphTitle(legend0); + pg1.setGraphTitle2(legend1); + pg1.setXaxisLegend("Log10( Core Film Thickness / metres )"); + pg1.setYaxisLegend("Effective Refractive Index (kz/ko)"); + + // Plot graph + pg1.plot(); + + // Return calculated curve values + return curve; + } + + // Calculate and plot a TM dispersion curve + // Graph title not provided + public double[][] plotDispersionCurveTM(double lowThickness, double highThickness, int numberOfPoints, double modeNumber){ + String legend1 = " "; + return this.plotDispersionCurveTM(lowThickness, highThickness, numberOfPoints, modeNumber, legend1); + } + + // Calculate and plot a TM dispersion curve + // Graph title provided + public double[][] plotDispersionCurveTM(double lowThickness, double highThickness, int numberOfPoints, double modeNumber, String legend1){ + + //Calculate curve + double[][] curve = dispersionCurveTM(lowThickness, highThickness, numberOfPoints, modeNumber); + + // Create instance of PlotGraph + PlotGraph pg2 = new PlotGraph(curve); + int lineOption = 3; + if(numberOfPoints<100)lineOption = 1; + pg2.setLine(lineOption); + pg2.setPoint(0); + String legend0 = "Dispersion curve: TM mode - mode number " + (int)modeNumber; + pg2.setGraphTitle(legend0); + pg2.setGraphTitle2(legend1); + pg2.setXaxisLegend("Log10( Core Film Thickness / metres )"); + pg2.setYaxisLegend("Effective Refractive Index (kz/ko)"); + + // Plot graph + pg2.plot(); + + // Return calculated curve values + return curve; + } + + // PLOT FITTED DISPERSION CURVE + // Graph title not provided + public void plotFittedDispersionCurves(){ + String legend = "PlanarWaveguide.plotDispersion - Dispersion Plot"; + this.plotFittedDispersionCurve(legend); + } + + // Graph title provided + public void plotFittedDispersionCurve(String legend){ + + if(!this.calculationDone)this.calcCoreFilmRefractiveIndices(); + + // separate TE mode orders + ArrayList<Object> arraylTE = null; + int pOrderNumberTE = 0; + int pOrdersCheckedTE = 0; + int maximumNumberOfPoints = 0; + if(this.numberOfTEmeasurements>0){ + arraylTE = new ArrayList<Object>(); + boolean testModes = true; + int pOrder = 0; + int numberTestedPositive = 0; + while(testModes){ + int pNumber = 0; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + if(this.measurementsTE[i][3]==pOrder){ + pNumber++; + numberTestedPositive++; + arraylTE.add(new Double(this.measurementsTE[i][0])); + arraylTE.add(new Double(this.measurementsTE[i][1])); + } + } + arraylTE.add(2*pOrder, new Integer(pOrder)); + arraylTE.add(2*pOrder+1, new Integer(pNumber)); + if(pNumber>0)pOrderNumberTE++; + if(pNumber>maximumNumberOfPoints)maximumNumberOfPoints = pNumber; + if(numberTestedPositive==this.numberOfTEmeasurements){ + testModes=false; + } + else{ + pOrder++; + } + } + pOrdersCheckedTE = pOrder; + } + int numberOfCurves = pOrderNumberTE; + + // separate TM mode orders + ArrayList<Object> arraylTM = null; + int pOrderNumberTM = 0; + int pOrdersCheckedTM = 0; + if(this.numberOfTMmeasurements>0){ + arraylTM = new ArrayList<Object>(); + boolean testModes = true; + int pOrder = 0; + int numberTestedPositive = 0; + while(testModes){ + int pNumber = 0; + for(int i=0; i<this.numberOfTMmeasurements; i++){ + if(this.measurementsTM[i][3]==pOrder){ + pNumber++; + numberTestedPositive++; + arraylTM.add(new Double(this.measurementsTM[i][0])); + arraylTM.add(new Double(this.measurementsTM[i][1])); + } + } + arraylTM.add(2*pOrder, new Integer(pOrder)); + arraylTM.add(2*pOrder+1, new Integer(pNumber)); + if(pNumber>0)pOrderNumberTM++; + if(pNumber>maximumNumberOfPoints)maximumNumberOfPoints = pNumber; + if(numberTestedPositive==this.numberOfTMmeasurements){ + testModes=false; + } + else{ + pOrder++; + } + } + pOrdersCheckedTM = pOrder; + } + numberOfCurves += pOrderNumberTM; + numberOfCurves *= 2; + if(maximumNumberOfPoints<200)maximumNumberOfPoints = 200; + + + // Set up plotting data arrays + double[][] plotData = PlotGraph.data(numberOfCurves, maximumNumberOfPoints); + double[] modeNumber = new double[numberOfCurves]; + String[] modeType = new String[numberOfCurves]; + + int atCurveNumber = 0; + int plotNumber = 0; + // TE mode curves + int arraylIndex = 2*(pOrdersCheckedTE+1); + int arraylHeaderIndex = 1; + double tempD = 0.0D; + int tempI = 0; + + if(this.numberOfTEmeasurements>0){ + int testVec = 0; + int arraylSize = arraylTE.size(); + while(testVec<arraylSize){ + // Check mode number has associated experimental data + tempI = ((Integer)arraylTE.get(arraylHeaderIndex)).intValue(); + testVec++; + if(tempI>0){ + modeType[atCurveNumber] = "TE"; + modeType[atCurveNumber+1] = "TE"; + modeNumber[atCurveNumber] = ((Integer)arraylTE.get(arraylHeaderIndex-1)).intValue(); + modeNumber[atCurveNumber+1] = modeNumber[atCurveNumber]; + testVec++; + + // experimental data curve + double[] tempThick = new double[tempI]; + double[] tempRefra = new double[tempI]; + for(int i=0; i<tempI; i++){ + tempThick[i] = ((Double)arraylTE.get(arraylIndex++)).doubleValue(); + tempRefra[i] = ((Double)arraylTE.get(arraylIndex++)).doubleValue(); + testVec += 2; + } + double[] log10TempThick = tempThick.clone(); + for(int i=0; i<tempI; i++)log10TempThick[i] = Fmath.log10(tempThick[i]); + + plotData[plotNumber++] = log10TempThick; + plotData[plotNumber++] = tempRefra; + + // sort into ascending thicknesses + Fmath.selectionSort(tempThick, tempRefra, tempThick, tempRefra); + + // calculated curve + double[][] curveTE = dispersionCurveTE(tempThick[0], tempThick[tempI-1], maximumNumberOfPoints, modeNumber[atCurveNumber]); + plotData[plotNumber++] = curveTE[0]; + plotData[plotNumber++] = curveTE[1]; + + atCurveNumber += 2; + } + arraylHeaderIndex =+ 2; + } + } + + // TM mode curves + arraylIndex = 2*(pOrdersCheckedTM+1); + arraylHeaderIndex = 1; + tempD = 0.0D; + tempI = 0; + + if(this.numberOfTMmeasurements>0){ + int testVec = 0; + int arraylSize = arraylTM.size(); + while(testVec<arraylSize){ + // Check mode number has associated experimental data + tempI = ((Integer)arraylTM.get(arraylHeaderIndex)).intValue(); + testVec++; + if(tempI>0){ + modeType[atCurveNumber] = "TM"; + modeType[atCurveNumber+1] = "TM"; + modeNumber[atCurveNumber] = ((Integer)arraylTM.get(arraylHeaderIndex-1)).intValue(); + testVec++; + modeNumber[atCurveNumber+1] = modeNumber[atCurveNumber]; + + // experimental data curve + double[] tempThick = new double[tempI]; + double[] tempRefra = new double[tempI]; + for(int i=0; i<tempI; i++){ + tempThick[i] = ((Double)arraylTM.get(arraylIndex++)).doubleValue(); + tempRefra[i] = ((Double)arraylTM.get(arraylIndex++)).doubleValue(); + testVec += 2; + } + double[] log10TempThick = tempThick.clone(); + for(int i=0; i<tempI; i++)log10TempThick[i] = Fmath.log10(tempThick[i]); + + plotData[plotNumber++] = log10TempThick; + plotData[plotNumber++] = tempRefra; + + // sort into ascending thicknesses + Fmath.selectionSort(tempThick, tempRefra, tempThick, tempRefra); + + // calculated curve + double[][] curveTM = dispersionCurveTM(tempThick[0], tempThick[tempI-1], maximumNumberOfPoints, modeNumber[atCurveNumber]); + plotData[plotNumber++] = curveTM[0]; + plotData[plotNumber++] = curveTM[1]; + + atCurveNumber += 2; + } + arraylHeaderIndex =+ 2; + } + } + + // Create instance of PlotGraph + PlotGraph pg0 = new PlotGraph(plotData); + + int[] lineOptions = new int[numberOfCurves]; + for(int i=0; i<numberOfCurves; i+=2){ + lineOptions[i] = 0; + lineOptions[i+1] = 3; + if(maximumNumberOfPoints<100)lineOptions[i+1] = 1; + } + pg0.setLine(lineOptions); + + int[] pointOptions = new int[numberOfCurves]; + int jj = 1; + for(int i=0; i<numberOfCurves; i+=2){ + pointOptions[i] = jj; + pointOptions[i+1] = 0; + jj++; + } + pg0.setPoint(pointOptions); + + pg0.setGraphTitle(legend); + pg0.setXaxisLegend("Log10( Core Film Thickness / metres )"); + pg0.setYaxisLegend("Effective Refractive Index (kz/ko)"); + + // Plot graphs + pg0.plot(); + } + + // CALCULATION OF THE SUPERSTRATE REFRACTIVE INDEX + public void calcSuperstrateRefractiveIndex(){ + if(!this.setMeasurements)throw new IllegalArgumentException("Either no thickness, angle/effective refractive index, mode number data has been entered or a key subclass variable, e.g. coupling prism corner angle has not been entered"); + if(!this.setWavelength)throw new IllegalArgumentException("No wavelength has been entered"); + if(!this.setSubstrate)throw new IllegalArgumentException("No substrate refractive index has been entered"); + if(!this.setCore)throw new IllegalArgumentException("No core layer refractive index has been entered"); + + // Set the bounds and eliminate points where effective ref. index < substrate or superstrate ref. index + this.lowerBound = 1.0D; + this.upperBound = this.coreFilmRefractiveIndex; + + if(this.numberOfTEmeasurements>0)this.eliminatedTE = new boolean[this.numberOfTEmeasurements]; + int elimNumberTE = 0; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + this.eliminatedTE[i] = false; + if(this.measurementsTE[i][1]>this.coreFilmRefractiveIndex){ + System.out.println("TE mode measurement point, " + i + ", eliminated as the effective refractive index, " + this.measurementsTE[i][1] + ", lies above the physical limit, " + this.coreFilmRefractiveIndex); + this.eliminatedTE[i] = true; + elimNumberTE++; + } + else{ + if(this.upperBound>this.measurementsTE[i][1])this.upperBound = this.measurementsTE[i][1]; + } + } + if(elimNumberTE>0){ + int newNumber = this.numberOfTEmeasurements - elimNumberTE; + if(newNumber==0){ + this.numberOfTEmeasurements = 0; + } + else{ + double[][] temp = new double[newNumber][3]; + int nIndex = 0; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + if(!this.eliminatedTE[i]){ + temp[nIndex][0] = this.measurementsTE[i][0]; + temp[nIndex][1] = this.measurementsTE[i][1]; + temp[nIndex][2] = this.measurementsTE[i][2]; + temp[nIndex][3] = this.measurementsTE[i][3]; + nIndex++; + } + } + this.measurementsTE = temp; + this.numberOfTEmeasurements = newNumber; + this.numberOfMeasurements = this.numberOfTEmeasurements + this.numberOfTMmeasurements; + } + } + this.thicknessesUsedTE = new double[this.numberOfTEmeasurements]; + this.calcEffectRefrIndicesTE = new double[this.numberOfTEmeasurements]; + for(int i=0; i<this.numberOfTEmeasurements; i++)this.thicknessesUsedTE[i] = this.measurementsTE[i][0]; + this.minimumTEmodeEffectiveRefractiveIndex = this.upperBound; + + this.upperBound = 0.0D; + if(this.numberOfTMmeasurements>0)this.eliminatedTM = new boolean[this.numberOfTMmeasurements]; + int elimNumberTM = 0; + for(int i=0; i<this.numberOfTMmeasurements; i++){ + this.eliminatedTM[i] = false; + if(this.measurementsTM[i][1]>this.coreFilmRefractiveIndex){ + System.out.println("TM mode measurement point, " + i + ", eliminated as the effective refractive index, " + this.measurementsTM[i][1] + ", lies above the physical limit, " + this.coreFilmRefractiveIndex); + this.eliminatedTM[i] = true; + elimNumberTM++; + } + else{ + if(this.upperBound>this.measurementsTM[i][1])this.upperBound = this.measurementsTM[i][1]; + } + } + if(elimNumberTM>0){ + int newNumber = this.numberOfTMmeasurements - elimNumberTM; + if(newNumber==0){ + this.numberOfTMmeasurements = 0; + } + else{ + double[][] temp = new double[newNumber][3]; + int nIndex = 0; + for(int i=0; i<this.numberOfTMmeasurements; i++){ + if(!this.eliminatedTM[i]){ + temp[nIndex][0] = this.measurementsTM[i][0]; + temp[nIndex][1] = this.measurementsTM[i][1]; + temp[nIndex][2] = this.measurementsTM[i][2]; + temp[nIndex][3] = this.measurementsTM[i][3]; + nIndex++; + } + } + this.measurementsTM = temp; + this.numberOfTMmeasurements = newNumber; + this.numberOfMeasurements = this.numberOfTEmeasurements + this.numberOfTMmeasurements; + } + } + this.thicknessesUsedTM = new double[this.numberOfTMmeasurements]; + this.calcEffectRefrIndicesTM = new double[this.numberOfTMmeasurements]; + for(int i=0; i<this.numberOfTMmeasurements; i++)this.thicknessesUsedTM[i] = this.measurementsTM[i][0]; + this.minimumTMmodeEffectiveRefractiveIndex = this.upperBound; + + if(this.numberOfMeasurements==0)throw new IllegalArgumentException("All data points rejected as lying outside the physically meaningful bounds"); + + // call the root search methods to obtain the superstrate refractive index/indices + if(this.numberOfTEmeasurements>0)this.calcTEmodeSuperstrateRefractiveIndices(); + if(this.numberOfTMmeasurements>0)this.calcTMmodeSuperstrateRefractiveIndices(); + + // Calculate the overall mean and standard deviation of the superstrate refractive index + if(this.numberOfTEmeasurements>0 && this.numberOfTMmeasurements==0){ + this.superstrateRefractiveIndex = this.meanTEmodeSuperstrateRefractiveIndex; + this.sdSuperstrateRefractiveIndex = this.sdTEmodeSuperstrateRefractiveIndex; + } + else{ + if(this.numberOfTMmeasurements>0 && this.numberOfTEmeasurements==0){ + this.superstrateRefractiveIndex = this.meanTMmodeSuperstrateRefractiveIndex; + this.sdSuperstrateRefractiveIndex = this.sdTMmodeSuperstrateRefractiveIndex; + } + else{ + double[] values = new double[this.numberOfMeasurements]; + double[] weights = new double[this.numberOfMeasurements]; + for(int i=0; i<this.numberOfTEmeasurements; i++){ + values[i] = this.calcSuperstrateTEmodeRI[i]; + weights[i] = this.measurementsTE[i][2]; + } + for(int i=0; i<this.numberOfTMmeasurements; i++){ + values[i+this.numberOfTEmeasurements] = this.calcSuperstrateTMmodeRI[i]; + weights[i+this.numberOfTEmeasurements] = this.measurementsTM[i][2]; + } + this.superstrateRefractiveIndex = Stat.mean(values, weights); + this.sdSuperstrateRefractiveIndex = Stat.standardDeviation(values, weights); + } + } + + this.superstrateRefractiveIndex2 = this.superstrateRefractiveIndex*this.superstrateRefractiveIndex; + this.minimumEffectiveRefractiveIndex = Math.min(this.minimumTEmodeEffectiveRefractiveIndex, this.minimumTMmodeEffectiveRefractiveIndex); + this.superCalculationDone = true; + } + + // Calculate TE mode refractive indices + public void calcTEmodeSuperstrateRefractiveIndices(){ + + this.calcSuperstrateTEmodeRI = new double[this.numberOfTEmeasurements]; + + // Create instance of the class holding the TE mode core film refractive indexfunction + FunctTEsuper func = new FunctTEsuper(); + + // Set function parameters + func.coreFilmRefractiveIndex2 = this.coreFilmRefractiveIndex2; + func.ko = this.ko; + + double[] weights = new double[this.numberOfTEmeasurements]; + this.lowerBound = 1.0D; + this.upperBound = this.minimumTEmodeEffectiveRefractiveIndex; + + for(int i=0; i<this.numberOfTEmeasurements; i++){ + weights[i] = this.measurementsTE[i][2]; + + // set further function parameters + func.thickness = this.measurementsTE[i][0]; + func.effectiveRefractiveIndex2 = this.measurementsTE[i][1]*this.measurementsTE[i][1]; + func.modeNumber = this.measurementsTE[i][3]; + + // call root searching method, bisection, to obtain core refractive index + RealRoot rr = new RealRoot(); + rr.noBoundsExtensions(); + rr.setTolerance(this.tolerance); + this.calcSuperstrateTEmodeRI[i] = rr.bisect(func, this.lowerBound, this.upperBound); + } + + // Calculate mean and sd + if(this.numberOfTEmeasurements>1){ + this.meanTEmodeSuperstrateRefractiveIndex = Stat.mean(this.calcSuperstrateTEmodeRI, weights); + this.sdTEmodeSuperstrateRefractiveIndex = Stat.standardDeviation(this.calcSuperstrateTEmodeRI, weights); + } + else{ + this.meanTEmodeSuperstrateRefractiveIndex = this.calcSuperstrateTEmodeRI[0]; + } + } + + // Calculate TM mode refractive indices + public void calcTMmodeSuperstrateRefractiveIndices(){ + + this.calcSuperstrateTMmodeRI = new double[this.numberOfTMmeasurements]; + + // Create instance of the class holding the TM mode core film refractive indexfunction + FunctTMsuper func = new FunctTMsuper(); + + // Set function parameters + func.coreFilmRefractiveIndex2 = this.coreFilmRefractiveIndex2; + func.ko = this.ko; + + double[] weights = new double[this.numberOfTMmeasurements]; + this.lowerBound = 1.0D; + this.upperBound = this.minimumTMmodeEffectiveRefractiveIndex; + + for(int i=0; i<this.numberOfTMmeasurements; i++){ + weights[i] = this.measurementsTM[i][2]; + + // set further function parameters + func.thickness = this.measurementsTM[i][0]; + func.effectiveRefractiveIndex2 = this.measurementsTM[i][1]*this.measurementsTM[i][1]; + func.modeNumber = this.measurementsTM[i][3]; + + // call root searching method, bisection, to obtain core refractive index + RealRoot rr = new RealRoot(); + rr.noBoundsExtensions(); + rr.setTolerance(this.tolerance); + this.calcSuperstrateTMmodeRI[i] = rr.bisect(func, this.lowerBound, this.upperBound); + } + + // Calculate mean and sd + if(this.numberOfTMmeasurements>1){ + this.meanTMmodeSuperstrateRefractiveIndex = Stat.mean(this.calcSuperstrateTMmodeRI, weights); + this.sdTMmodeSuperstrateRefractiveIndex = Stat.standardDeviation(this.calcSuperstrateTMmodeRI, weights); + } + else{ + this.meanTMmodeSuperstrateRefractiveIndex = this.calcSuperstrateTMmodeRI[0]; + } + } +} + +// Class containing function with the root search for the TE mode core film refractive index +class FunctTE implements RealRootFunction{ + + public double substrateRefractiveIndex2 = 0.0D; + public double superstrateRefractiveIndex2 = 0.0D; + public double effectiveRefractiveIndex2 = 0.0D; + public double prismRefractiveIndex2 = 0.0D; + public double ko = 0.0D; + public double prismToWaveguideGap = 0.0D; + public boolean setPrismToWaveguideGap = false; + public double thickness = 0.0D; + public double modeNumber = 0; + + public double function(double x){ + double y = 0.0D; + + // function calculation + double coreFilmRefractiveIndex2 = x*x; + double zetaSub = Math.sqrt(this.effectiveRefractiveIndex2 - this.substrateRefractiveIndex2); + double zetaSuper = Math.sqrt(this.effectiveRefractiveIndex2 - this.superstrateRefractiveIndex2); + double zetaFilm = Math.sqrt(coreFilmRefractiveIndex2 - this.effectiveRefractiveIndex2); + double zetaPrism = Math.sqrt(this.prismRefractiveIndex2 - this.effectiveRefractiveIndex2); + double gammaSuper = Math.atan2(zetaSuper, zetaFilm); + y = Math.PI*modeNumber - this.thickness*this.ko*zetaFilm; + y += (gammaSuper + Math.atan2(zetaSub, zetaFilm)); + if(this.setPrismToWaveguideGap) y += (Math.sin(gammaSuper)*Math.cos( Math.atan2(zetaSuper, zetaPrism))*Math.exp(-2.0D*this.prismToWaveguideGap*this.ko*zetaSuper)); + + return y; + } +} + +// Class containing function with the root search for the TM mode core film refractive index +class FunctTM implements RealRootFunction{ + + public double substrateRefractiveIndex2 = 0.0D; + public double superstrateRefractiveIndex2 = 0.0D; + public double effectiveRefractiveIndex2 = 0.0D; + public double prismRefractiveIndex2 = 0.0D; + public double ko = 0.0D; + public double prismToWaveguideGap = 0.0D; + public boolean setPrismToWaveguideGap = false; + public double thickness = 0.0D; + public double modeNumber = 0; + + public double function(double x){ + double y = 0.0D; + + // function calculation + double coreFilmRefractiveIndex2 = x*x; + double zetaSub = Math.sqrt(this.effectiveRefractiveIndex2 - this.substrateRefractiveIndex2); + double zetaSuper = Math.sqrt(this.effectiveRefractiveIndex2 - this.superstrateRefractiveIndex2); + double zetaFilm = Math.sqrt(coreFilmRefractiveIndex2 - this.effectiveRefractiveIndex2); + double zetaPrism = Math.sqrt(this.prismRefractiveIndex2 - this.effectiveRefractiveIndex2); + double gammaSuper = Math.atan2(coreFilmRefractiveIndex2*zetaSuper, this.superstrateRefractiveIndex2*zetaFilm); + y = Math.PI*modeNumber - this.thickness*this.ko*zetaFilm; + y += (gammaSuper + Math.atan2(coreFilmRefractiveIndex2*zetaSub, this.substrateRefractiveIndex2*zetaFilm)); + if(this.setPrismToWaveguideGap) y += (Math.sin(gammaSuper)*Math.cos( Math.atan2(zetaSuper*this.prismRefractiveIndex2, zetaPrism*this.superstrateRefractiveIndex2))*Math.exp(-2.0D*this.prismToWaveguideGap*zetaSuper)); + + return y; + } +} + +// Class containing function with the root search for the TE mode effective refractive index +class FunctTEplot implements RealRootFunction{ + + public double substrateRefractiveIndex2 = 0.0D; + public double superstrateRefractiveIndex2 = 0.0D; + public double coreFilmRefractiveIndex2 = 0.0D; + public double prismRefractiveIndex2 = 0.0D; + public double ko = 0.0D; + public double prismToWaveguideGap = 0.0D; + public boolean setPrismToWaveguideGap = false; + public double thickness = 0.0D; + public double modeNumber = 0; + + public double function(double x){ + double y = 0.0D; + + // function calculation + double effectiveRefractiveIndex2 = x*x; + double zetaSub = Math.sqrt(effectiveRefractiveIndex2 - this.substrateRefractiveIndex2); + double zetaSuper = Math.sqrt(effectiveRefractiveIndex2 - this.superstrateRefractiveIndex2); + double zetaFilm = Math.sqrt(this.coreFilmRefractiveIndex2 - effectiveRefractiveIndex2); + double zetaPrism = Math.sqrt(this.prismRefractiveIndex2 - effectiveRefractiveIndex2); + double gammaSuper = Math.atan2(zetaSuper, zetaFilm); + y = Math.PI*modeNumber - this.thickness*this.ko*zetaFilm; + y += (gammaSuper + Math.atan2(zetaSub, zetaFilm)); + if(this.setPrismToWaveguideGap) y += (Math.sin(gammaSuper)*Math.cos( Math.atan2(zetaSuper, zetaPrism))*Math.exp(-2.0D*this.prismToWaveguideGap*this.ko*zetaSuper)); + + return y; + } +} + +// Class containing function with the root search for the TM mode effective refractive index +class FunctTMplot implements RealRootFunction{ + + public double substrateRefractiveIndex2 = 0.0D; + public double superstrateRefractiveIndex2 = 0.0D; + public double coreFilmRefractiveIndex2 = 0.0D; + public double prismRefractiveIndex2 = 0.0D; + public double ko = 0.0D; + public double prismToWaveguideGap = 0.0D; + public boolean setPrismToWaveguideGap = false; + public double thickness = 0.0D; + public double modeNumber = 0; + + public double function(double x){ + double y = 0.0D; + + double effectiveRefractiveIndex2 = x*x; + double zetaSub = Math.sqrt(effectiveRefractiveIndex2 - this.substrateRefractiveIndex2); + double zetaSuper = Math.sqrt(effectiveRefractiveIndex2 - this.superstrateRefractiveIndex2); + double zetaFilm = Math.sqrt(this.coreFilmRefractiveIndex2 - effectiveRefractiveIndex2); + double zetaPrism = Math.sqrt(this.prismRefractiveIndex2 - effectiveRefractiveIndex2); + double gammaSuper = Math.atan2(this.coreFilmRefractiveIndex2*zetaSuper, this.superstrateRefractiveIndex2*zetaFilm); + y = Math.PI*modeNumber - this.thickness*this.ko*zetaFilm; + y += (gammaSuper + Math.atan2(this.coreFilmRefractiveIndex2*zetaSub, this.substrateRefractiveIndex2*zetaFilm)); + if(this.setPrismToWaveguideGap) y += (Math.sin(gammaSuper)*Math.cos( Math.atan2(zetaSuper*this.prismRefractiveIndex2, zetaPrism*this.superstrateRefractiveIndex2))*Math.exp(-2.0D*this.prismToWaveguideGap*zetaSuper)); + + return y; + } +} + +// Class containing function with the root search for the TE mode superstrate refractive index +class FunctTEsuper implements RealRootFunction{ + + public double substrateRefractiveIndex2 = 0.0D; + public double effectiveRefractiveIndex2 = 0.0D; + public double coreFilmRefractiveIndex2 = 0.0D; + public double ko = 0.0D; + public double thickness = 0.0D; + public double modeNumber = 0; + + public double function(double x){ + double y = 0.0D; + + // function calculation + double superstrateRefractiveIndex2 = x*x; + double zetaSub = Math.sqrt(this.effectiveRefractiveIndex2 - this.substrateRefractiveIndex2); + double zetaSuper = Math.sqrt(effectiveRefractiveIndex2 - superstrateRefractiveIndex2); + double zetaFilm = Math.sqrt(this.coreFilmRefractiveIndex2 - this.effectiveRefractiveIndex2); + y = Math.PI*modeNumber - this.thickness*this.ko*zetaFilm; + y += (Math.atan2(zetaSuper, zetaFilm) + Math.atan2(zetaSub, zetaFilm)); + + return y; + } +} + +// Class containing function with the root search for the TM mode superstrate refractive index +class FunctTMsuper implements RealRootFunction{ + + public double substrateRefractiveIndex2 = 0.0D; + public double effectiveRefractiveIndex2 = 0.0D; + public double coreFilmRefractiveIndex2 = 0.0D; + public double ko = 0.0D; + public double thickness = 0.0D; + public double modeNumber = 0; + + public double function(double x){ + double y = 0.0D; + + double superstrateRefractiveIndex2 = x*x; + double zetaSub = Math.sqrt(this.effectiveRefractiveIndex2 - this.substrateRefractiveIndex2); + double zetaSuper = Math.sqrt(effectiveRefractiveIndex2 - superstrateRefractiveIndex2); + double zetaFilm = Math.sqrt(this.coreFilmRefractiveIndex2 - this.effectiveRefractiveIndex2); + y = Math.PI*modeNumber - this.thickness*this.ko*zetaFilm; + y += (Math.atan2(this.coreFilmRefractiveIndex2*zetaSuper, superstrateRefractiveIndex2*zetaFilm) + Math.atan2(this.coreFilmRefractiveIndex2*zetaSub, this.substrateRefractiveIndex2*zetaFilm)); + + return y; + } +} diff --git a/src/main/java/flanagan/optics/PrismCoupler.java b/src/main/java/flanagan/optics/PrismCoupler.java new file mode 100755 index 0000000000000000000000000000000000000000..c138c9e6ea4446619512de748f2ecc8b4e3d14c1 --- /dev/null +++ b/src/main/java/flanagan/optics/PrismCoupler.java @@ -0,0 +1,589 @@ +/* +* PrismCoupler Class +* +* Methods for: +* determining the refractive index of a waveguiding thin film +* in an asymmetric slab waveguide from the prism coupling angle and the core layer thickness +* +* obtaining the normalised propagation vector versus guiding layer thickness +* dispersion curve for an asymmetric slab waveguide +* +* This is a subclass of the superclasses PlanarWaveguideCoupler +* +* Author: Dr Michael Thomas Flanagan. +* +* Created: April 2006 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/PrismCoupler.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) April 2006 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.optics; + +import flanagan.math.Fmath; +import flanagan.analysis.ErrorProp; +import flanagan.plot.*; +import flanagan.optics.*; + +public class PrismCoupler extends PlanarWaveguide{ + + // CLASS VARIABLES + + private double[] thicknessesTE = null; // thicknesses for experimental TE mode thimeasurements + private double[] anglesDegTE = null; // coupling angles, in degrees, for experimental TE mode measurements + private double[] anglesRadTE = null; // coupling angles, in radians, for experimental TE mode measurements + private double[] errorsDegTE = null; // errors in coupling angles, in degrees, for experimental TE mode measurements + private double[] errorsRadTE = null; // errors in coupling angles, in radians, for experimental TE mode measurements + private double[] modeNumbersTE = null; // mode numbers for experimental TE mode measurements + private double[] effectiveRefractiveIndicesTE = null; // effective refractive indices for TE mode measurements + private double[] effectiveErrorsTE = null; // propagated errors for effective refractive indices for TE mode measurements + private int numberOfTEmeasurementsPrism = 0; // number of TE mode thickness measurement + private boolean setMeasurementsTEprism = false; // = true when TE mode measurements entered + private boolean setTEerrors = false; // = true if TE mode errors are set + + private double[] thicknessesTM = null; // thicknesses for experimental TM mode thimeasurements + private double[] anglesDegTM = null; // coupling angles, in degrees, for experimental TM mode measurements + private double[] anglesRadTM = null; // coupling angles, in radians, for experimental TM mode measurements + private double[] errorsDegTM = null; // errors in coupling angles, in degrees, for experimental TM mode measurements + private double[] errorsRadTM = null; // errors in coupling angles, in radians, for experimental TM mode measurements + private double[] modeNumbersTM = null; // mode numbers for experimental TM mode measurements + private double[] effectiveRefractiveIndicesTM = null; // effective refractive indices for TM mode measurements + private double[] effectiveErrorsTM = null; // propagated errors for effective refractive indices for TM mode measurements + private int numberOfTMmeasurementsPrism = 0; // number of TM mode thickness measurement + private boolean setMeasurementsTMprism = false; // = true when TM mode measurements entered + private boolean setTMerrors = false; // = true if TM mode errors are set + + + private int numberOfMeasurementsPrism = 0; // total number of thickness measurements entered + private boolean setMeasurementsPrism = false; // = true when TE and/or TM mode measurements entered + + private boolean setPrismRI = false; // = true when prism refractive index entered + private double prismAngleAlphaDeg = 0.0D; // Coupling prism angle alpha (in degrees) + private double prismAngleAlphaRad = 0.0D; // Coupling prism angle alpha (in radians) + private boolean setPrismAlpha = false; // = true when prism angle, alpha, entered + + + // CONSTRUCTOR + public PrismCoupler(){ + } + + // COUPLING PRISM + // Enter refractive index + public void setPrismRefractiveIndex(double refInd){ + super.prismRefractiveIndex = refInd; + super.prismRefractiveIndex2 = refInd*refInd; + this.setPrismRI = true; + if(this.setMeasurementsPrism && this.setPrismAlpha)this.calcEffectiveRefractiveIndices(); + } + + // Enter coupling prism angle, alpha, in degrees + public void setPrismAngleAlpha(double angle){ + this.prismAngleAlphaDeg = angle; + this.prismAngleAlphaRad = Math.toRadians(angle); + this.setPrismAlpha = true; + if(this.setMeasurementsPrism && this.setPrismRI)this.calcEffectiveRefractiveIndices(); + } + + // Enter coupling prism to waveguide gap distance in metres + public void setPrismToWaveguideGap(double gap){ + super.prismToWaveguideGap = gap; + super.setPrismToWaveguideGap = true; + } + + // THICKNESS (metres), COUPLING ANGLE (degrees) AND MODE NUMBER DATA + // Enter TE mode data for a single measurement without error + public void enterTEmodeData(double thickness, double angle, double modeNumber){ + if(this.setMeasurementsTEprism){ + if(setErrorsTE)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTEmeasurementsPrism + 1; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++)hold[i] = this.thicknessesTE[i]; + hold[this.numberOfTEmeasurementsPrism] = thickness; + this.thicknessesTE = hold; + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++)hold[i] = this.anglesDegTE[i]; + hold[this.numberOfTEmeasurementsPrism] = angle; + this.anglesDegTE = hold; + this.anglesRadTE = hold; + this.errorsDegTE = hold; + this.errorsRadTE = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTE[i] = Math.toRadians(this.anglesDegTE[i]); + this.errorsDegTE[i] = 0.0D; + this.errorsRadTE[i] = 0.0D; + } + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++)hold[i] = this.modeNumbersTE[i]; + hold[this.numberOfTEmeasurementsPrism] = modeNumber; + this.numberOfTEmeasurementsPrism = nNew; + } + else{ + this.thicknessesTE = new double[1]; + this.thicknessesTE[0] = thickness; + this.anglesDegTE = new double[1]; + this.anglesDegTE[0] = angle; + this.anglesRadTE = new double[1]; + this.anglesRadTE[0] = Math.toRadians(angle); + this.errorsDegTE = new double[1]; + this.errorsDegTE[0] = 0.0D; + this.errorsRadTE = new double[1]; + this.errorsRadTE[0] = 0.0D; + this.modeNumbersTE = new double[1]; + this.modeNumbersTE[0] = modeNumber; + this.numberOfTEmeasurementsPrism = 1; + } + this.numberOfMeasurementsPrism = this.numberOfTEmeasurementsPrism + this.numberOfTMmeasurementsPrism; + this.setMeasurementsTEprism = true; + this.setMeasurementsPrism = true; + if(this.setPrismAlpha && this.setPrismAlpha)this.calcTEmodeEffectiveRefractiveIndices(); + } + + + + // Enter TM mode data for a single measurement without error + public void enterTMmodeData(double thickness, double angle, double modeNumber){ + if(this.setMeasurementsTMprism){ + if(this.setTMerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTMmeasurementsPrism + 1; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++)hold[i] = this.thicknessesTM[i]; + hold[this.numberOfTMmeasurementsPrism] = thickness; + this.thicknessesTM = hold; + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++)hold[i] = this.anglesDegTM[i]; + hold[this.numberOfTMmeasurementsPrism] = angle; + this.anglesDegTM = hold; + this.anglesRadTM = hold; + this.errorsDegTM = hold; + this.errorsRadTM = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTM[i] = Math.toRadians(this.anglesDegTM[i]); + this.errorsDegTM[i] = 0.0D; + this.errorsRadTM[i] = 0.0D; + } + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++)hold[i] = this.modeNumbersTM[i]; + hold[this.numberOfTMmeasurementsPrism] = modeNumber; + this.numberOfTMmeasurementsPrism = nNew; + } + else{ + this.thicknessesTM = new double[1]; + this.thicknessesTM[0] = thickness; + this.anglesDegTM = new double[1]; + this.anglesDegTM[0] = angle; + this.anglesRadTM = new double[1]; + this.anglesRadTM[0] = Math.toRadians(angle); + this.errorsDegTM = new double[1]; + this.errorsDegTM[0] = 0.0D; + this.errorsRadTM = new double[1]; + this.errorsRadTM[0] = 0.0D; + this.modeNumbersTM = new double[1]; + this.modeNumbersTM[0] = modeNumber; + this.numberOfTMmeasurementsPrism = 1; + } + this.numberOfMeasurementsPrism = this.numberOfTEmeasurementsPrism + this.numberOfTMmeasurementsPrism; + this.setMeasurementsTMprism = true; + this.setMeasurementsPrism = true; + if(this.setPrismAlpha && this.setPrismRI)this.calcTMmodeEffectiveRefractiveIndices(); + } + + // Enter TE mode data for a range of measurements without errors + public void enterTEmodeData(double[] thicknesses, double[] angles, double[] modeNumbers){ + int o = thicknesses.length; + int n = angles.length; + if(n!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of coupling angles, " + n); + int m = modeNumbers.length; + if(m!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of mode numbers, " + m); + + if(this.setMeasurementsTEprism){ + if(this.setTEerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTEmeasurementsPrism + o; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++)hold[i] = this.thicknessesTE[i]; + for(int i=0; i<o; i++)hold[this.numberOfTEmeasurementsPrism+i] = thicknesses[i]; + this.thicknessesTE = hold; + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++)hold[i] = this.anglesDegTE[i]; + for(int i=0; i<o; i++)hold[this.numberOfTEmeasurementsPrism+i] = angles[i]; + this.anglesDegTE = hold; + this.anglesRadTE = hold; + this.errorsDegTE = hold; + this.errorsRadTE = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTE[i] = Math.toRadians(this.anglesDegTE[i]); + this.errorsDegTE[i] = 0.0D; + this.errorsRadTE[i] = 0.0D; + } + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++)hold[i] = this.modeNumbersTE[i]; + for(int i=0; i<o; i++)hold[this.numberOfTEmeasurementsPrism+i] = modeNumbers[i]; + this.numberOfTEmeasurementsPrism = nNew; + } + else{ + this.numberOfTEmeasurementsPrism = o; + this.thicknessesTE = thicknesses; + this.anglesDegTE = angles; + this.anglesRadTE = new double[o]; + this.errorsDegTE = new double[o]; + this.errorsRadTE = new double[o]; + for(int i=0; i<o; i++){ + this.anglesRadTE[i] = Math.toRadians(angles[i]); + this.errorsDegTE[i] = 0.0D; + this.errorsRadTE[i] = 0.0D; + } + this.modeNumbersTE = modeNumbers; + } + this.numberOfMeasurementsPrism = this.numberOfTEmeasurementsPrism + this.numberOfTMmeasurementsPrism; + this.setMeasurementsTEprism = true; + this.setMeasurementsPrism = true; + if(this.setPrismAlpha && this.setPrismRI)this.calcTEmodeEffectiveRefractiveIndices(); + } + + // Enter TM mode data for a range of measurements without errors + public void enterTMmodeData(double[] thicknesses, double[] angles, double[] modeNumbers){ + int o = thicknesses.length; + int n = angles.length; + if(n!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of coupling angles, " + n); + int m = modeNumbers.length; + if(m!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of mode numbers, " + m); + + if(this.setMeasurementsTMprism){ + if(this.setTMerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTMmeasurementsPrism + o; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++)hold[i] = this.thicknessesTM[i]; + for(int i=0; i<o; i++)hold[this.numberOfTMmeasurementsPrism+i] = thicknesses[i]; + this.thicknessesTM = hold; + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++)hold[i] = this.anglesDegTM[i]; + for(int i=0; i<o; i++)hold[this.numberOfTMmeasurementsPrism+i] = angles[i]; + this.anglesDegTM = hold; + this.anglesRadTM = hold; + this.errorsDegTM = hold; + this.errorsRadTM = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTM[i] = Math.toRadians(this.anglesDegTM[i]); + this.errorsDegTM[i] = 0.0D; + this.errorsRadTM[i] = 0.0D; + } + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++)hold[i] = this.modeNumbersTM[i]; + for(int i=0; i<o; i++)hold[this.numberOfTMmeasurementsPrism+i] = modeNumbers[i]; + this.numberOfTMmeasurementsPrism = nNew; + } + else{ + this.numberOfTMmeasurementsPrism = o; + this.thicknessesTM = thicknesses; + this.anglesDegTM = angles; + this.anglesRadTM = new double[o]; + this.errorsDegTM = new double[o]; + this.errorsRadTM = new double[o]; + for(int i=0; i<o; i++){ + this.anglesRadTM[i] = Math.toRadians(angles[i]); + this.errorsDegTM[i] = 0.0D; + this.errorsRadTM[i] = 0.0D; + } + this.modeNumbersTM = modeNumbers; + } + this.numberOfMeasurementsPrism = this.numberOfTEmeasurementsPrism + this.numberOfTMmeasurementsPrism; + this.setMeasurementsTMprism = true; + this.setMeasurementsPrism = true; + if(this.setPrismAlpha && this.setPrismRI)this.calcTMmodeEffectiveRefractiveIndices(); + } + + // Enter TE mode data for a single measurement with error + public void enterTEmodeData(double thickness, double angle, double error, double modeNumber){ + if(this.setMeasurementsTEprism){ + if(!this.setTEerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTEmeasurementsPrism + 1; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++)hold[i] = this.thicknessesTE[i]; + hold[this.numberOfTEmeasurementsPrism] = thickness; + this.thicknessesTE = hold; + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++)hold[i] = this.anglesDegTE[i]; + hold[this.numberOfTEmeasurementsPrism] = angle; + this.anglesDegTE = hold; + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++)hold[i] = this.errorsDegTE[i]; + hold[this.numberOfTEmeasurementsPrism] = error; + this.errorsDegTE = hold; + this.anglesRadTE = hold; + this.errorsRadTE = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTE[i] = Math.toRadians(this.anglesDegTE[i]); + this.errorsRadTE[i] = Math.toRadians(this.errorsDegTE[i]); + } + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++)hold[i] = this.modeNumbersTE[i]; + hold[this.numberOfTEmeasurementsPrism] = modeNumber; + this.numberOfTEmeasurementsPrism = nNew; + } + else{ + this.thicknessesTE = new double[1]; + this.thicknessesTE[0] = thickness; + this.anglesDegTE = new double[1]; + this.anglesDegTE[0] = angle; + this.anglesRadTE = new double[1]; + this.anglesRadTE[0] = Math.toRadians(angle); + this.errorsDegTE = new double[1]; + this.errorsDegTE[0] = error; + this.errorsRadTE = new double[1]; + this.errorsRadTE[0] = Math.toRadians(error); + this.modeNumbersTE = new double[1]; + this.modeNumbersTE[0] = modeNumber; + this.numberOfTEmeasurementsPrism = 1; + } + this.numberOfMeasurementsPrism = this.numberOfTEmeasurementsPrism + this.numberOfTMmeasurementsPrism; + this.setMeasurementsTEprism = true; + this.setTEerrors = true; + this.setMeasurementsPrism = true; + if(this.setPrismAlpha && this.setPrismRI)this.calcTEmodeEffectiveRefractiveIndices(); + } + + + + // Enter TM mode data for a single measurement with error + public void enterTMmodeData(double thickness, double angle, double error, double modeNumber){ + if(this.setMeasurementsTMprism){ + if(!this.setTMerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTMmeasurementsPrism + 1; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++)hold[i] = this.thicknessesTM[i]; + hold[this.numberOfTMmeasurementsPrism] = thickness; + this.thicknessesTM = hold; + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++)hold[i] = this.anglesDegTM[i]; + hold[this.numberOfTMmeasurementsPrism] = angle; + this.anglesDegTM = hold; + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++)hold[i] = this.errorsDegTM[i]; + hold[this.numberOfTMmeasurementsPrism] = error; + this.errorsDegTM = hold; + this.anglesRadTM = hold; + this.errorsRadTM = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTM[i] = Math.toRadians(this.anglesDegTM[i]); + this.errorsRadTM[i] = Math.toRadians(this.errorsDegTM[i]); + } + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++)hold[i] = this.modeNumbersTM[i]; + hold[this.numberOfTMmeasurementsPrism] = modeNumber; + this.numberOfTMmeasurementsPrism = nNew; + } + else{ + this.thicknessesTM = new double[1]; + this.thicknessesTM[0] = thickness; + this.anglesDegTM = new double[1]; + this.anglesDegTM[0] = angle; + this.anglesRadTM = new double[1]; + this.anglesDegTM[0] = Math.toRadians(angle); + this.errorsDegTM = new double[1]; + this.errorsDegTM[0] = error; + this.errorsRadTM = new double[1]; + this.errorsDegTM[0] = Math.toRadians(error); + this.modeNumbersTM = new double[1]; + this.modeNumbersTM[0] = modeNumber; + this.numberOfTMmeasurementsPrism = 1; + } + this.numberOfMeasurementsPrism = this.numberOfTEmeasurementsPrism + this.numberOfTMmeasurementsPrism; + this.setMeasurementsTMprism = true; + this.setTMerrors = true; + this.setMeasurementsPrism = true; + if(this.setPrismAlpha && this.setPrismRI)this.calcTMmodeEffectiveRefractiveIndices(); + } + + // Enter TE mode data for a range of measurements with errors + public void enterTEmodeData(double[] thicknesses, double[] angles, double[] errors, double[] modeNumbers){ + int o = thicknesses.length; + int n = angles.length; + if(n!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of coupling angles, " + n); + int m = modeNumbers.length; + if(m!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of mode numbers, " + m); + + if(this.setMeasurementsTEprism){ + if(!this.setTEerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTEmeasurementsPrism + o; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++)hold[i] = this.thicknessesTE[i]; + for(int i=0; i<o; i++)hold[this.numberOfTEmeasurementsPrism+i] = thicknesses[i]; + this.thicknessesTE = hold; + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++)hold[i] = this.anglesDegTE[i]; + for(int i=0; i<o; i++)hold[this.numberOfTEmeasurementsPrism+i] = angles[i]; + this.anglesDegTE = hold; + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++)hold[i] = this.errorsDegTE[i]; + for(int i=0; i<o; i++)hold[this.numberOfTEmeasurementsPrism+i] = errors[i]; + this.errorsDegTE = hold; + this.anglesRadTE = hold; + this.errorsRadTE = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTE[i] = Math.toRadians(this.anglesDegTE[i]); + this.errorsRadTE[i] = Math.toRadians(this.errorsDegTE[i]); + } + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++)hold[i] = this.modeNumbersTE[i]; + for(int i=0; i<o; i++)hold[this.numberOfTEmeasurementsPrism+i] = modeNumbers[i]; + this.numberOfTEmeasurementsPrism = nNew; + } + else{ + this.numberOfTEmeasurementsPrism = o; + this.thicknessesTE = thicknesses; + this.anglesDegTE = angles; + this.anglesRadTE = new double[o]; + this.errorsDegTE = errors; + this.errorsRadTE = new double[o]; + for(int i=0; i<o; i++){ + this.anglesRadTE[i] = Math.toRadians(angles[i]); + this.errorsRadTE[i] = Math.toRadians(errors[i]); + } + this.modeNumbersTE = modeNumbers; + } + this.numberOfMeasurementsPrism = this.numberOfTEmeasurementsPrism + this.numberOfTMmeasurementsPrism; + this.setMeasurementsTEprism = true; + this.setTEerrors = true; + this.setMeasurementsPrism = true; + if(this.setPrismAlpha && this.setPrismRI)this.calcTEmodeEffectiveRefractiveIndices(); + } + + // Enter TM mode data for a range of measurements without errors + public void enterTMmodeData(double[] thicknesses, double[] angles, double[] errors, double[] modeNumbers){ + int o = thicknesses.length; + int n = angles.length; + if(n!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of coupling angles, " + n); + int m = modeNumbers.length; + if(m!=o)throw new IllegalArgumentException("number of thicknesses, " + o + ", does not equal the number of mode numbers, " + m); + + if(this.setMeasurementsTMprism){ + if(!this.setTMerrors)throw new IllegalArgumentException("All Entered data must either all have associated errors entered or all have no associated errors entered"); + int nNew = this.numberOfTMmeasurementsPrism + o; + double[] hold = new double[nNew]; + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++)hold[i] = this.thicknessesTM[i]; + for(int i=0; i<o; i++)hold[this.numberOfTMmeasurementsPrism+i] = thicknesses[i]; + this.thicknessesTM = hold; + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++)hold[i] = this.anglesDegTM[i]; + for(int i=0; i<o; i++)hold[this.numberOfTMmeasurementsPrism+i] = angles[i]; + this.anglesDegTM = hold; + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++)hold[i] = this.errorsDegTM[i]; + for(int i=0; i<o; i++)hold[this.numberOfTMmeasurementsPrism+i] = errors[i]; + this.errorsDegTM = hold; + this.anglesRadTM = hold; + this.errorsRadTM = hold; + for(int i=0; i<nNew; i++){ + this.anglesRadTM[i] = Math.toRadians(this.anglesDegTM[i]); + this.errorsRadTM[i] = Math.toRadians(this.errorsDegTM[i]); + } + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++)hold[i] = this.modeNumbersTM[i]; + for(int i=0; i<o; i++)hold[this.numberOfTMmeasurementsPrism+i] = modeNumbers[i]; + this.numberOfTMmeasurementsPrism = nNew; + } + else{ + this.numberOfTMmeasurementsPrism = o; + this.thicknessesTM = thicknesses; + this.anglesDegTM = angles; + this.errorsDegTM = errors; + this.anglesRadTM = new double[o]; + this.errorsRadTM = new double[o]; + for(int i=0; i<o; i++){ + this.anglesRadTM[i] = Math.toRadians(angles[i]); + this.errorsRadTM[i] = Math.toRadians(errors[i]); + } + this.modeNumbersTM = modeNumbers; + } + this.numberOfMeasurementsPrism = this.numberOfTEmeasurementsPrism + this.numberOfTMmeasurementsPrism; + this.setMeasurementsTMprism = true; + this.setTMerrors = true; + this.setMeasurementsPrism = true; + if(this.setPrismAlpha && this.setPrismRI)this.calcTMmodeEffectiveRefractiveIndices(); + } + + + // Clear entered thickness, effective refractive index and mode number data + // so new dat may be entered without it being appended to the existing data + public void clearData(){ + this.numberOfTEmeasurementsPrism = 0; + this.setMeasurementsTEprism = false; + + this.numberOfTMmeasurementsPrism = 0; + this.setMeasurementsTMprism = false; + + super.numberOfMeasurements = 0; + super.setMeasurements = false; + super.setWeights = false; + + super.numberOfTEmeasurements = 0; + super.setMeasurementsTE = false; + + super.numberOfTMmeasurements = 0; + super.setMeasurementsTM = false; + } + + // CALCULATION OF THE EFFECTIVE REFRACTIVE INDEX/INDICES + // Calculate all effective refractive indices + public void calcEffectiveRefractiveIndices(){ + if(this.setMeasurementsTEprism)this.calcTEmodeEffectiveRefractiveIndices(); + if(this.setMeasurementsTMprism)this.calcTMmodeEffectiveRefractiveIndices(); + } + + // Calculate TE mode effective refractive indices + public void calcTEmodeEffectiveRefractiveIndices(){ + this.effectiveRefractiveIndicesTE = new double[this.numberOfTEmeasurementsPrism]; + this.effectiveErrorsTE = new double[this.numberOfTEmeasurementsPrism]; + + if(this.setTEerrors){ + ErrorProp alpha = new ErrorProp(this.prismAngleAlphaRad, 0.0D); + ErrorProp prismRI = new ErrorProp(super.prismRefractiveIndex, 0.0D); + ErrorProp airRI = new ErrorProp(RefractiveIndex.air(super.wavelength), 0.0D); + ErrorProp phi = new ErrorProp(); + ErrorProp angle = new ErrorProp(); + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++){ + angle.reset(this.anglesRadTE[i], this.errorsRadTE[i]); + phi = (angle.over(prismRI)).times(airRI); + phi = ErrorProp.asin(phi); + phi = alpha.plus(phi); + phi = prismRI.times(ErrorProp.sin(phi)); + this.effectiveRefractiveIndicesTE[i] = phi.getValue(); + this.effectiveErrorsTE[i] = phi.getError(); + } + super.enterTEmodeData(this.thicknessesTE, this.effectiveRefractiveIndicesTE, this.effectiveErrorsTE, this.modeNumbersTE); + } + else{ + for(int i=0; i<this.numberOfTEmeasurementsPrism; i++){ + double phi = this.prismAngleAlphaRad + Math.asin(RefractiveIndex.air(super.wavelength)*this.anglesRadTE[i]/super.prismRefractiveIndex); + this.effectiveRefractiveIndicesTE[i] = super.prismRefractiveIndex*Math.sin(phi); + } + super.enterTEmodeData(this.thicknessesTE, this.effectiveRefractiveIndicesTE, this.modeNumbersTE); + } + } + + // Calculate TM mode effective refractive indices + public void calcTMmodeEffectiveRefractiveIndices(){ + this.effectiveRefractiveIndicesTM = new double[this.numberOfTMmeasurementsPrism]; + this.effectiveErrorsTM = new double[this.numberOfTMmeasurementsPrism]; + + if(this.setTMerrors){ + ErrorProp alpha = new ErrorProp(this.prismAngleAlphaRad, 0.0D); + ErrorProp prismRI = new ErrorProp(super.prismRefractiveIndex, 0.0D); + ErrorProp airRI = new ErrorProp(RefractiveIndex.air(super.wavelength), 0.0D); + ErrorProp phi = new ErrorProp(); + ErrorProp angle = new ErrorProp(); + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++){ + angle.reset(this.anglesRadTM[i], this.errorsRadTM[i]); + phi = (angle.over(prismRI)).times(airRI); + phi = ErrorProp.asin(phi); + phi = alpha.plus(phi); + phi = prismRI.times(ErrorProp.sin(phi)); + this.effectiveRefractiveIndicesTM[i] = phi.getValue(); + this.effectiveErrorsTM[i] = phi.getError(); + } + super.enterTMmodeData(this.thicknessesTM, this.effectiveRefractiveIndicesTM, this.effectiveErrorsTM, this.modeNumbersTM); + } + else{ + for(int i=0; i<this.numberOfTMmeasurementsPrism; i++){ + double phi = this.prismAngleAlphaRad + Math.asin(RefractiveIndex.air(super.wavelength)*this.anglesRadTM[i]/super.prismRefractiveIndex); + this.effectiveRefractiveIndicesTM[i] = super.prismRefractiveIndex*Math.sin(phi); + } + super.enterTMmodeData(this.thicknessesTM, this.effectiveRefractiveIndicesTM, this.modeNumbersTM); + } + } +} + diff --git a/src/main/java/flanagan/optics/Reflectivity.java b/src/main/java/flanagan/optics/Reflectivity.java new file mode 100755 index 0000000000000000000000000000000000000000..32a26f55971319fe4ac0c650751f5d3d5be702fe --- /dev/null +++ b/src/main/java/flanagan/optics/Reflectivity.java @@ -0,0 +1,3236 @@ +/* +* Reflectivity Class +* +* Methods for calculating the reflection of light from +* the surface of a multilayer of dielectic and/or metal layers +* and of fitting experimental data to a reflectivity, transmissivity +* or evanescent field strength scan against angle or wavelength +* +* Methods for fitting data to a reflectivty, transmissivitty or evanescent field +* scan over a range of incident angles at a single wavelength +* +* Author: Dr Michael Thomas Flanagan. +* +* Created: February/March/April 2006 +* Developed from earlier C++ and Fortran programs +* Revised 26 April 2006, 5-7 July 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Refflectivity.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) March 2006 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.optics; + +import flanagan.complex.*; +import flanagan.math.Fmath; +import flanagan.plot.*; +import flanagan.analysis.*; +import java.util.ArrayList; +import java.lang.reflect.Array; + +public class Reflectivity{ + + // CLASS VARIABLES + + private int numberOfLayers = 0; // number of layers including the semi-infinite layer at both outer faces + private int numberOfInterfaces = 0; // number of interlayer interfaces, i.e. number of layers minus one + + private Complex[][] refractiveIndices = null; // refractive indices of the layers at all wavelengths (number of wavelength, number of layers) + private Complex[] meanRefractiveIndices = null; // mean refractive indices of each layer + private boolean refractSet = false; // = true when refractive indices entered + private boolean[] refractLayerSet = null; // = true for layer i when refractive indices entered for layer i + private boolean meanRefractUsed = false; // = true when mean refractive indices used + + private Complex[][] relativeMagneticPermeabilities = null; // relative magnetic permeabilities of the layers + // default values = 1.0 + private Complex[] meanRelativeMagneticPermeabilities = null;// mean relative magnetic permeabilities of the layers + private boolean magneticSet = false; // = true when relative magnetic permeabilities entered + private boolean meanMagneticUsed = false; // = true when mean relative magnetic permeabilities used + + private double[][] absorptionCoefficients = null; // absorption coefficents of the layers at all wavelengths + // default values = 0.0; + private boolean absorbSet = false; // = true when absorbtivity or extinction coefficients entered + + private double[] thicknesses = null; // thicknesses (in metres) of the layers + private double[] distances = null; // cumulative thicknesses (in metres) + private boolean thickSet = false; // = true when thicknesses entered + private boolean[] thickLayerSet = null; // = true for layer i when thicknesses entered for layer i + + private int numberOfWavelengths = 0; // number of wavelengths in wavelength scan + private double[] wavelengths = null; // wavelengths (in metres) in scan + private double[] frequencies = null; // frequencies (in Hz) in scan + private double[] omega = null; // radial frequencies (in radians) in scan + private int[] origWavelIndices = null; // indices of the wavelengths as entered before sort into lowest to highest + private boolean wavelSet = false; // = true when wavelengths entered + private boolean freqSet = false; // = true when frequencies entered + private boolean wavelNumberSet = false; // = true when number of wavelengths set + + private double[] incidentAngleDeg = null; // incident angles measured from the normal in degrees + private double[] incidentAngleRad = null; // incident angles measured from the normal in radians + private int[] incidentAngleIndices = null; // indices of original incident angles after sorting into ascending order + private int numberOfIncidentAngles = 0; // number of incident angles in angular scan + private boolean incidentAngleSet = false; // = true when the incident angles have been entered + + private String mode = null; // polarisation mode: TE, TM, unpolarised or mixed + private double eVectorAngleDeg = 0.0D; // angle between the electric vector of the incident light and + // the plane normal to the reflecting surfac in degrees + private double eVectorAngleRad = 0.0D; // angle between the electric vector of the incident light and + // the plane normal to the reflecting surfac in radians + private double teFraction = 0.0D; // fraction of light in the TE mode + private double tmFraction = 0.0D; // fraction of light in the TM mode + private boolean modeSet = false; // = true when mode set + + private Complex[][][] koVector = null; // ko vector [wavelength] [incident angle] [layer] + private Complex[][][] kVector = null; // k vector [wavelength] [incident angle] [layer] + private Complex[][][] kxVector = null; // kx vector [wavelength] [incident angle] [layer] + private Complex[][][] kzVector = null; // kz vector [wavelength] [incident angle] [layer] + + private double[][] reflectivities = null; // reflectivities [wavelength] [incident angle] + private double[][] transmissivities = null; // transmissivities [wavelength] [incident angle] + private double[][] powerLosses = null; // power loss on transmission relative to an input power of 1mW over 1 sq. metre [wavelength] [incident angle] + private Complex[][] reflectCoeffTE = null; // TE reflection coefficient [wavelength] [incident angle] + private Complex[][] reflectCoeffTM = null; // TM reflection coefficient [wavelength] [incident angle] + private Complex[][] transmitCoeffTE = null; // TE transmission coefficient [wavelength] [incident angle] + private Complex[][] transmitCoeffTM = null; // TM transmissiom coefficient [wavelength] [incident angle] + + private double[][] reflectPhaseShiftRadTE = null; // TE reflection phase shift (radians) [wavelength] [incident angle] + private double[][] reflectPhaseShiftRadTM = null; // TM reflection phase shift (radians) [wavelength] [incident angle] + private double[][] transmitPhaseShiftRadTE = null; // TE transmission phase shift (radians) [wavelength] [incident angle] + private double[][] transmitPhaseShiftRadTM = null; // TM transmissiom phase shift (radians) [wavelength] [incident angle] + private double[][] reflectPhaseShiftDegTE = null; // TE reflection phase shift (degrees) [wavelength] [incident angle] + private double[][] reflectPhaseShiftDegTM = null; // TM reflection phase shift (degrees) [wavelength] [incident angle] + private double[][] transmitPhaseShiftDegTE = null; // TE transmission phase shift (degrees) [wavelength] [incident angle] + private double[][] transmitPhaseShiftDegTM = null; // TM transmissiom phase shift (degrees) [wavelength] [incident angle] + + private double[][] evanescentFields = null; // integrated evanescent fields [wavelength] [incident angle] + private double fieldDistance = Double.POSITIVE_INFINITY; // distance into evanescent field over which intensity is integrated + private boolean fieldIntensityCalc= false; // = true when field intensity calculated for non-infinite field distance + private double[][] penetrationDepths= null; // Evanescent field penetration depth [wavelength] [incident angle] + private double[][] transmitAnglesRad = null; // transmitted angles in radians [wavelength] [incident angle] + private double[][] transmitAnglesDeg = null; // transmitted angles in degrees [wavelength] [incident angle] + + private boolean singleReflectCalculated = false; // = true when only a single angular relectivity has been calculated + private boolean angularReflectCalculated = false; // = true when an angular relectivity scan has been calculated + private boolean wavelengthReflectCalculated = false; // = true when an wavelength relectivity scan has been calculated + private boolean wavelengthAndAngularReflectCalculated = false; // = true when angular for each wavelength relectivity scan has been calculated + + private double mu0overEps0 = Fmath.MU_0/Fmath.EPSILON_0; // permeability of free space over permittivity of free space + private double impedance = Math.sqrt(mu0overEps0); // characteristic impedance of free space + + private int wavelengthAxisOption = 1; // = 1 when wavelength/frequency x-axis in plotting methods = wavelength + // = 2 when wavelength/frequency x-axis in plotting methods = frequency, Hz + // = 3 when wavelength/frequency x-axis in plotting methods = radians + + private double[] experimentalData = null; // experimental data [incident angle] + private double[] experimentalWeights = null; // error in each experimental point [incident angle] + private double[] calculatedData = null; // calculated data [incident angle] + + private int numberOfDataPoints = 0; // number of experimental data points + private boolean experimentalDataSet = false; // = true when experimental data entered + private boolean weightingOption = false; // = true if experimental weightings (other than unity) entered + + private int numberOfEstimatedParameters = 0; // number of parameters to be estimated in non-linear regression method + private int[] thicknessEstimateIndices = null; // indices of the thicknesses to be estimated by non-linear regression + private int[] refractIndexRealEstimateIndices = null; // indices of the Real[refractive indices] to be estimated by non-linear regression + private int[] refractIndexImagEstimateIndices = null; // indices of the Imag[refractive indices] to be estimated by non-linear regression + private int[] absorptionCoeffEstimateIndices = null; // indices of the absorption coefficients to be estimated by non-linear regression + private int[] magneticPermRealEstimateIndices = null; // indices of the Real[relative magnetic permeability] to be estimated by non-linear regression + private int[] magneticPermImagEstimateIndices = null; // indices of the Imag[relative magnetic permeability] to be estimated by non-linear regression + + private boolean refractIndexImagEstimateSet = false; // = true when indices of the Imag[refractive indices] set + private boolean absorptionCoeffEstimateSet = false; // = true when indices of the absorption coefficients set + + private int thicknessEstimateNumber = 0; // number of the thicknesses to be estimated by non-linear regression + private int refractIndexRealEstimateNumber = 0; // number of the Real[refractive indices] to be estimated by non-linear regression + private int refractIndexImagEstimateNumber = 0; // number of the Imag[refractive indices] to be estimated by non-linear regression + private int absorptionCoeffEstimateNumber = 0; // number of the absorption coefficients to be estimated by non-linear regression + private int magneticPermRealEstimateNumber = 0; // number of the Real[relative magnetic permeabilities] to be estimated by non-linear regression + private int magneticPermImagEstimateNumber = 0; // number of the Imag[relative magnetic permeabilities] to be estimated by non-linear regression + + private double fieldScalingFactor = 0.0D; // scaling factor between calculated and experimental field values + + public int regressionOption = 0; // Regression option + // = 1; reflectivity versus angle + // = 2; transmissivity versus angle + // = 3; evanescent field versus angle + public int degreesOfFreedom = 0; // degrees of freedom (non-linear regression method) + + // CONSTRUCTOR + + public Reflectivity(int n){ + this.numberOfLayers = n; + this.numberOfInterfaces = n-1; + if(n<2)throw new IllegalArgumentException("There must be at least two layers, i.e. at least one interface"); + + this.meanRelativeMagneticPermeabilities = Complex.oneDarray(this.numberOfLayers, 1.0D, 0.0D); + + this.meanRefractiveIndices = Complex.oneDarray(this.numberOfLayers); + this.refractLayerSet = new boolean[this.numberOfLayers]; + for(int i=0; i<this.numberOfLayers; i++)this.refractLayerSet[i] = false; + + this.thicknesses = new double[this.numberOfLayers]; + this.thicknesses[0] = Double.NEGATIVE_INFINITY; + this.thicknesses[this.numberOfLayers-1] = Double.POSITIVE_INFINITY; + this.thickLayerSet = new boolean[this.numberOfLayers]; + this.thickLayerSet[0] = true; + for(int i=1; i<this.numberOfLayers-2; i++)this.thickLayerSet[i] = false; + this.thickLayerSet[this.numberOfLayers-1] = true; + + this.distances = new double[this.numberOfInterfaces]; + } + + // POLARISATION MODE + + // Enter polarisation mode - TE or TM or unpolarised + public void setMode(String mode){ + if(mode.equalsIgnoreCase("TE") || mode.equalsIgnoreCase("transverse electric")){ + this.mode = "TE"; + this.teFraction = 1.0D; + this.tmFraction = 0.0D; + this.eVectorAngleDeg = 0.0D; + this.eVectorAngleRad = 0.0D; + } + else{ + if(mode.equalsIgnoreCase("TM") || mode.equalsIgnoreCase("transverse magnetic")){ + this.mode = "TM"; + this.teFraction = 0.0D; + this.tmFraction = 1.0D; + this.eVectorAngleDeg = 90.0D; + this.eVectorAngleRad = Math.PI/2.0D; + } + else{ + if(mode.equalsIgnoreCase("unpolarised") || mode.equalsIgnoreCase("unpolarized") || mode.equalsIgnoreCase("none")){ + this.mode = "unpolarised"; + this.teFraction = 0.5D; + this.tmFraction = 0.5D; + this.eVectorAngleDeg = 45.0D; + this.eVectorAngleRad = Math.PI/4.0D; + } + else{ + throw new IllegalArgumentException("mode must be TE, TM or unpolarised; it cannot be " + mode); + } + } + } + this.modeSet = true; + } + + // Enter angle between incident light electric vector and the plane normal to the reflecting plane in degrees + public void setMode(double modeAngle){ + this.mode = "mixed"; + this.eVectorAngleDeg = modeAngle; + this.eVectorAngleRad = Math.toRadians(modeAngle); + this.teFraction = Math.sin(this.eVectorAngleRad); + this.teFraction *= this.teFraction; + this.tmFraction = 1.0D - this.teFraction; + this.modeSet = true; + } + + // Return the fractional TE component + public double fractionInTEmode(){ + return this.teFraction; + } + + // Return the fractional TM component + public double fractionInTMmode(){ + return this.tmFraction; + } + + // INCIDENT ANGLES + + // Enter a single incident angle (degrees) + public void setIncidentAngle(double incidentAngle){ + double[] incident = {incidentAngle}; + this.setIncidentAngle(incident); + } + + // Enter an array of incident angles (degrees) + public void setIncidentAngle(double[] incidentAngle){ + this.numberOfIncidentAngles = incidentAngle.length; + this.incidentAngleIndices = new int[this.numberOfIncidentAngles]; + this.incidentAngleDeg = new double[this.numberOfIncidentAngles]; + Fmath.selectionSort(incidentAngle, this.incidentAngleDeg, this.incidentAngleIndices); + if(this.experimentalDataSet){ + if(this.numberOfDataPoints!=this.numberOfIncidentAngles)throw new IllegalArgumentException("Number of experimental reflectivities " + this.numberOfDataPoints + " does not equal the number of incident angles " + this.numberOfIncidentAngles); + double[] temp = this.experimentalData.clone(); + for(int i=0; i<this.numberOfIncidentAngles;i++)this.experimentalData[i] = temp[this.incidentAngleIndices[i]]; + } + this.incidentAngleRad = new double[this.numberOfIncidentAngles]; + for(int i=0; i<this.numberOfIncidentAngles;i++)this.incidentAngleRad[i] = Math.toRadians(this.incidentAngleDeg[i]); + this.incidentAngleSet = true; + } + + // Enter a range of nAngles incident angles [degrees] ranging, in equal increments from angleLow to angleHigh + public void setIncidentAngle(double angleLow, double angleHigh, int nAngles){ + this.numberOfIncidentAngles = nAngles; + double increment = (angleHigh - angleLow)/(nAngles - 1); + double[] incidentAngles = new double[nAngles]; + incidentAngles[0] = angleLow; + for(int i=1; i<nAngles-1; i++)incidentAngles[i] = incidentAngles[i-1] + increment; + incidentAngles[nAngles-1] = angleHigh; + this.setIncidentAngle(incidentAngles); + } + + // Return the incident angles (in degrees) + public double[] getIncidentAngles(){ + return this.incidentAngleDeg; + } + + // THICKNESSES + + // Enter layer thicknesses (metres) excluding outer semi-infinite layers + public void setThicknesses(double[] thick){ + int n = thick.length; + if(n!=this.numberOfLayers-2)throw new IllegalArgumentException("Number of thicknesses, " + n + ", does not match the number of layers minus the outer two semi-finite layers, " + (this.numberOfLayers-2)); + for(int i=1; i<this.numberOfLayers-1; i++)this.thicknesses[i] = thick[i-1]; + + // Calculate distances + this.distances[0] = 0.0D; + for(int i=1; i<this.numberOfInterfaces; i++)this.distances[i] = this.distances[i-1] + this.thicknesses[i]; + + for(int i=1; i<this.numberOfLayers-2; i++)this.thickLayerSet[i] = true; + this.thickSet = true; + } + + // Enter layer thicknesses (metres) for individual layer + public void setThicknesses(double thickness, int layerNumber){ + if(layerNumber<1 || layerNumber>this.numberOfLayers)throw new IllegalArgumentException("Layer number, " + layerNumber + ", must be in the range 1 to "+this.numberOfLayers); + this.thicknesses[layerNumber-1] = thickness; + + // Recalculate distances + this.distances[0] = 0.0D; + for(int i=1; i<this.numberOfInterfaces; i++)this.distances[i] = this.distances[i-1] + this.thicknesses[i]; + + this.thickLayerSet[layerNumber-1] = true; + int check = 0; + for(int i=0; i<this.numberOfLayers-i; i++)if(this.thickLayerSet[i])check++; + if(check==this.numberOfLayers)this.thickSet = true; + } + + // Return the layer thicknesses + public double[] getThicknesses(){ + return this.thicknesses; + } + + // WAVELENGTH AND FREQUENCIES + + // Enter wavelengths (metres) + public void setWavelength(double[] wavelengths){ + // set wavelengths + int n = wavelengths.length; + if(this.wavelNumberSet){ + if(n!=this.numberOfWavelengths)throw new IllegalArgumentException("The number of wavelengths entered, " + n + ", does not equal that previously set," + this.numberOfWavelengths); + } + this.numberOfWavelengths = n; + this.wavelengths = wavelengths; + this.wavelSet = true; + + // set refractive indices array dimensions + if(!refractSet)this.refractiveIndices = Complex.twoDarray(this.numberOfWavelengths, this.numberOfLayers); + + // fill out mean refractive indices if necessary + if(!this.wavelNumberSet){ + // Fill out refractive index arrays if mean values have been entered + if(this.meanRefractUsed){ + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + this.refractiveIndices[j][i] = this.meanRefractiveIndices[i]; + } + } + for(int i=0; i<this.numberOfLayers; i++)this.refractLayerSet[i] = true; + this.refractSet = true; + } + + // Calculate imaginary refractive indices arrays if absorption coefficients have been entered + // or otherwise set all absorption coefficients to zero + if(this.absorptionCoefficients!=null){ + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + if(this.refractiveIndices[i][j].getImag()==0.0D)this.refractiveIndices[j][i].setImag(absorptionCoefficients[j][i]*this.wavelengths[j]/(4.0D*Math.PI)); + } + } + } + else{ + this.absorptionCoefficients = new double[this.numberOfWavelengths][this.numberOfLayers]; + } + + // Fill out relative magnetic permeability arrays if empty + this.relativeMagneticPermeabilities = Complex.twoDarray(this.numberOfWavelengths, this.numberOfLayers); + if(this.meanMagneticUsed){ + // if mean values have been entered + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + this.relativeMagneticPermeabilities[j][i] = this.meanRelativeMagneticPermeabilities[i]; + } + } + this.magneticSet = true; + } + else{ + // if no values have been entered set all to unity + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + this.relativeMagneticPermeabilities[j][i] = Complex.plusOne(); + } + } + } + } + + // calculate frequencies + if(!freqSet){ + this.frequencies = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)this.frequencies[this.numberOfWavelengths-1-i] = Fmath.C_LIGHT/wavelengths[i]; + } + + // calculate radial frequencies + this.omega = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)this.omega[i] = 2.0D*Math.PI*frequencies[i]; + + this.wavelNumberSet = true; + } + + // Enter frequencies (Hz) + public void setFrequency(double[] frequency){ + // set frequencies + int n = frequency.length; + if(this.wavelNumberSet){ + if(n!=this.numberOfWavelengths)throw new IllegalArgumentException("The number of frequencies entered, " + n + ", does not equal that previously set," + this.numberOfWavelengths); + } + this.frequencies = frequency; + this.freqSet = true; + this.wavelengthAxisOption = 2; + + // set wavelengths + double[] wavelength = new double[n]; + for(int i=0; i<n; i++)wavelength[i] = Fmath.C_LIGHT/frequencies[n-1-i]; + this.setWavelength(wavelength); + } + + // Enter a range of nLambda wavelengths [metres] ranging, in equal increments from lambdaLow to lambdaHigh + public void setWavelength(double lambdaLow, double lambdaHigh, int nLambda){ + double increment = (lambdaHigh - lambdaLow)/(nLambda - 1); + double[] wavelength = new double[nLambda]; + wavelength[0] = lambdaLow; + for(int i=1; i<nLambda-1; i++)wavelength[i] = wavelength[i-1] + increment; + wavelength[nLambda-1] = lambdaHigh; + this.setWavelength(wavelength); + } + + // Enter a range of nFreq frequencies [Hz] ranging, in equal increments from freqLow to freqHigh + public void setFrequency(double freqLow, double freqHigh, int nFreq){ + double increment = (freqHigh - freqLow)/(nFreq - 1); + double[] frequency = new double[nFreq]; + frequency[0] = freqLow; + for(int i=1; i<nFreq-1; i++)frequency[i] = frequency[i-1] + increment; + frequency[nFreq-1] = freqHigh; + this.setFrequency(frequency); + } + + // Enter a single wavelength [metres] + public void setWavelength(double wavelength){ + double[] wavelengths = {wavelength}; + this.setWavelength(wavelengths); + } + + // Enter a single frequency [Hz] + public void setFrequency(double frequency){ + double[] frequencies = {frequency}; + this.setFrequency(frequencies); + } + + // Return the wavelengths + public double[] getWavelengths(){ + return this.wavelengths; + } + + // Return the radial frequencies + public double[] getRadialFrequencies(){ + return this.omega; + } + + // Sort wavelengths into increasing order + // with accompanying matchingrearrangement of the magnetic permeabilities and the absorption coefficients + private void sortWavelengths(){ + this.origWavelIndices = new int[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)this.origWavelIndices[i] = i; + if(this.numberOfWavelengths>1){ + // test if not in order + boolean test0 = true; + boolean test1 = false; + int ii = 1; + while(test0){ + if(this.wavelengths[ii]<this.wavelengths[ii-1]){ + test0 = false; + test1 = true; + } + else{ + ii++; + if(ii>=this.numberOfWavelengths)test0 = false; + } + } + if(test1){ + // reorder + ArrayList arrayl = Fmath.selectSortArrayList(wavelengths); + this.wavelengths = (double[])arrayl.get(1); + this.origWavelIndices = (int[])arrayl.get(2); + + Complex[][] tempC = new Complex[this.numberOfWavelengths][this.numberOfLayers]; + for(int i=0; i<this.numberOfWavelengths; i++){ + for(int j=0; j<this.numberOfLayers; j++){ + tempC[i][j] = this.refractiveIndices[this.origWavelIndices[i]][j]; + } + } + this.refractiveIndices = Complex.copy(tempC); + + for(int i=0; i<this.numberOfWavelengths; i++){ + for(int j=0; j<this.numberOfLayers; j++){ + tempC[i][j] = this.relativeMagneticPermeabilities[this.origWavelIndices[i]][j]; + } + } + this.relativeMagneticPermeabilities = Complex.copy(tempC); + + double[][] tempD = new double[this.numberOfWavelengths][this.numberOfLayers]; + for(int i=0; i<this.numberOfWavelengths; i++){ + for(int j=0; j<this.numberOfLayers; j++){ + tempD[i][j] = this.absorptionCoefficients[this.origWavelIndices[i]][j]; + } + } + this.absorptionCoefficients = tempD; + } + } + } + + // REFRACTIVE INDICES + + // Enter all individual refractive indices, as complex numbers + public void setRefractiveIndices(Complex[][] refractiveIndices){ + int n = refractiveIndices[0].length; + if(n!=this.numberOfLayers)throw new IllegalArgumentException("Number of refractive indices layers, " + n + ", does not match the number of layers, " + this.numberOfLayers); + int m = refractiveIndices.length; + if(this.wavelSet){ + if(m!=this.numberOfWavelengths)throw new IllegalArgumentException("Number of refractive indices wavelength sets, " + m + ", does not match the number of wavelengths already set, " + this.numberOfWavelengths); + } + + // set refractive indices + this.refractiveIndices = refractiveIndices; + for(int i=0; i<this.numberOfLayers; i++)this.refractLayerSet[i] = true; + this.refractSet = true; + this.wavelNumberSet = true; + + // calculate mean refractive index per layer + for(int i=0; i<this.numberOfLayers; i++){ + Complex sum = Complex.zero(); + for(int j=0; j<this.numberOfWavelengths; j++){ + sum.plusEquals(this.refractiveIndices[j][i]); + } + this.meanRefractiveIndices[i] = sum.over(this.numberOfWavelengths); + } + + // enter imaginary refractive indices if absorption coefficients have been entered + if(this.wavelSet && this.absorptionCoefficients!=null){ + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + if(this.refractiveIndices[j][i].getImag()==0.0D)this.refractiveIndices[j][i].setImag(absorptionCoefficients[j][i]*this.wavelengths[i]/(4.0D*Math.PI)); + } + } + } + // otherwise set absorption coefficients to zero + if(!this.absorbSet)absorptionCoefficients = new double[this.numberOfWavelengths][this.numberOfLayers]; + + // Fill out relative magnetic permeability arrays + if(!this.magneticSet){ + if(this.meanMagneticUsed){ + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + this.relativeMagneticPermeabilities[j][i] = this.meanRelativeMagneticPermeabilities[i]; + } + } + this.magneticSet = true; + } + else{ + this.relativeMagneticPermeabilities = Complex.twoDarray(this.numberOfWavelengths, this.numberOfLayers, 1.0D, 0.0D); + } + } + } + + // Enter all individual refractive indices, as real numbers + public void setRefractiveIndices(double[][] refractiveIndices){ + int n = refractiveIndices[0].length; + if(n!=this.numberOfLayers)throw new IllegalArgumentException("Number of refractive indices layers, " + n + ", does not match the number of layers, " + this.numberOfLayers); + int m = refractiveIndices.length; + if(this.wavelSet){ + if(m!=this.numberOfWavelengths)throw new IllegalArgumentException("Number of refractive indices wavelength sets, " + m + ", does not match the number of wavelengths already set, " + this.numberOfWavelengths); + } + Complex[][] complexRefractiveIndices = Complex.twoDarray(m, n); + for(int i=0; i<m; i++){ + for(int j=0; j<n; j++){ + complexRefractiveIndices[i][j].setReal(refractiveIndices[i][j]); + } + } + this.setRefractiveIndices(complexRefractiveIndices); + } + + // Enter mean refractive index for each layer, as complex numbers + public void setRefractiveIndices(Complex[] refractiveIndices){ + + // set refractive indices + int n = refractiveIndices.length; + if(n!=this.numberOfLayers)throw new IllegalArgumentException("Number of refrative indices layers, " + n + ", does not match the number of layers, " + this.numberOfLayers); + this.meanRefractiveIndices = refractiveIndices; + this.meanRefractUsed = true; + + if(this.wavelNumberSet){ + // Fill out individual refractive index arrays + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + this.refractiveIndices[j][i] = this.meanRefractiveIndices[i]; + } + } + for(int i=0; i<this.numberOfLayers; i++)this.refractLayerSet[i] = true; + this.refractSet = true; + } + + // enter imaginary refractive indices if absorption coefficients have been entered + if(this.absorptionCoefficients!=null && this.wavelSet){ + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + if(this.refractiveIndices[j][i].getImag()==0.0D)this.refractiveIndices[j][i].setImag(absorptionCoefficients[j][i]*this.wavelengths[j]/(4.0D*Math.PI)); + } + } + } + // otherwise set absorption coefficients to zero + if(this.absorptionCoefficients==null)absorptionCoefficients = new double[this.numberOfWavelengths][this.numberOfLayers]; + + + // Fill out relative magnetic permeability arrays + if(!this.magneticSet){ + if(!this.meanMagneticUsed){ + if(this.wavelNumberSet){ + this.relativeMagneticPermeabilities = Complex.twoDarray(this.numberOfWavelengths, this.numberOfLayers, 1.0D, 0.0D); + } + } + else{ + this.relativeMagneticPermeabilities = Complex.twoDarray(this.numberOfWavelengths, this.numberOfLayers); + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + this.relativeMagneticPermeabilities[j][i] = this.meanRelativeMagneticPermeabilities[i]; + } + } + this.magneticSet = true; + } + } + } + + // Enter mean refractive index for each layer, as real numbers + public void setRefractiveIndices(double[] refractiveIndices){ + int n = refractiveIndices.length; + if(n!=this.numberOfLayers)throw new IllegalArgumentException("Number of refrative indices, " + n + ", does not match the number of layers, " + this.numberOfLayers); + Complex[] complexRefractiveIndices = Complex.oneDarray(n); + for(int i=0; i<n; i++){ + complexRefractiveIndices[i].setReal(refractiveIndices[i]); + } + this.setRefractiveIndices(complexRefractiveIndices); + + } + + // Set refractive indices for an individual layer, as complex numbers + public void setRefractiveIndices(Complex[] refractiveIndices, int layerNumber){ + if(layerNumber<0 || layerNumber>this.numberOfLayers)throw new IllegalArgumentException("Layer number, " + layerNumber + ", must be in the range 1 to " + this.numberOfLayers); + int n = refractiveIndices.length; + if(this.wavelNumberSet){ + if(n!=this.numberOfWavelengths)throw new IllegalArgumentException("The number of refractive index wavelength values, " + n + ", does not match the number of wavelengths already entered, " + this.numberOfWavelengths); + + } + else{ + // Give dimensions to refractive index arrays - fill with mean if known + this.numberOfWavelengths = n; + this.wavelNumberSet = true; + this.refractiveIndices = Complex.twoDarray(this.numberOfLayers, this.numberOfWavelengths); + if(this.meanRefractUsed){ + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + this.refractiveIndices[j][i]=this.meanRefractiveIndices[i]; + } + } + for(int i=0; i<this.numberOfLayers; i++)this.refractLayerSet[i] = true; + this.refractSet = true; + } + // Give dimensions to relative permeabilities arrays - fill with mean if known + this.relativeMagneticPermeabilities = Complex.twoDarray(this.numberOfWavelengths, this.numberOfLayers, 1.0D, 0.0D); + + if(this.meanMagneticUsed){ + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + this.relativeMagneticPermeabilities[j][i]=this.meanRelativeMagneticPermeabilities[i]; + } + } + this.magneticSet = true; + } + } + + // fill layer values for layer identified in this method's argument list + layerNumber--; + this.refractiveIndices[layerNumber] = refractiveIndices; + this.refractLayerSet[layerNumber] = true; + int check = 0; + for(int i=0; i<this.numberOfLayers; i++)if(this.refractLayerSet[i])check++; + if(check==this.numberOfLayers)this.refractSet=true; + + // set imaginary refractive indices for this layer if some absorption coefficients already entered + if(this.absorptionCoefficients!=null){ + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + if(this.refractiveIndices[j][i].getImag()==0.0D)this.refractiveIndices[j][i].setImag(absorptionCoefficients[j][i]*this.wavelengths[j]/(4.0D*Math.PI)); + } + } + } + // otherwise set all absorption coefficients to zero + if(this.absorptionCoefficients==null)absorptionCoefficients = new double[this.numberOfWavelengths][this.numberOfLayers]; + + } + + // Set refractive indices for an individual layer, as real numbers + public void setRefractiveIndices(double[] refractiveIndices, int layerNumber){ + if(layerNumber<0 || layerNumber>this.numberOfLayers)throw new IllegalArgumentException("Layer number, " + layerNumber + ", must be in the range 1 to " + this.numberOfLayers); + int n = refractiveIndices.length; + if(this.wavelNumberSet){ + if(n!=this.numberOfWavelengths)throw new IllegalArgumentException("The number of refractive index wavelength values, " + n + ", does not match the number of wavelengths already entered, " + this.numberOfWavelengths); + } + Complex[] complexRefractiveIndices = Complex.oneDarray(n); + for(int i=0; i<n; i++){ + complexRefractiveIndices[i].setReal(refractiveIndices[i]); + } + this.setRefractiveIndices(complexRefractiveIndices, layerNumber); + } + + // Set mean refractive indices for an individual layer, as a complex number + public void setRefractiveIndices(Complex refractiveIndex, int layerNumber){ + if(this.wavelNumberSet){ + Complex[] complexRefractiveIndices = Complex.oneDarray(this.numberOfWavelengths); + for(int i=0; i<this.numberOfWavelengths; i++){ + complexRefractiveIndices[i] = refractiveIndex; + } + this.setRefractiveIndices(complexRefractiveIndices, layerNumber); + } + else{ + this.meanRefractiveIndices[layerNumber-1] = refractiveIndex; + this.meanRefractUsed = true; + } + } + + // Set mean refractive indices for an individual layer, as a real number + public void setRefractiveIndices(double refractiveIndex, int layerNumber){ + Complex complexRefractiveIndex = new Complex(refractiveIndex, 0.0D); + this.setRefractiveIndices(complexRefractiveIndex, layerNumber); + } + + // Return refractive indices + public Object getRefractiveIndices(){ + if(this.numberOfWavelengths==1){ + Complex[] ret = this.refractiveIndices[0]; + return (Object)ret; + } + else{ + return (Object)this.refractiveIndices; + } + } + + // ABSORPTION COEFFICIENTS + + // Enter absorption coefficients [default = 0], single wavelength + public void setAbsorptionCoefficients(double[] absorptionCoefficients){ + // set absorption coefficients arrays + int n = absorptionCoefficients.length; + if(n!=this.numberOfLayers)throw new IllegalArgumentException("Number of absorption coefficients sets, " + n + ", does not match the number of layers, " + this.numberOfLayers); + this.absorptionCoefficients = new double[1][n]; + this.absorptionCoefficients[0] = absorptionCoefficients; + this.absorbSet = true; + + if(this.refractSet){ + for(int i=0; i<this.numberOfLayers; i++){ + if(this.refractiveIndices[0][i].getImag()==0.0D)this.refractiveIndices[0][i].setImag(this.absorptionCoefficients[0][i]*this.wavelengths[0]/(4.0D*Math.PI)); + } + } + } + + + // Enter absorption coefficients [default = 0], range of wavelengths + public void setAbsorptionCoefficients(double[][] absorptionCoefficients){ + // set absorption coefficients arrays + int n = absorptionCoefficients[0].length; + if(n!=this.numberOfLayers)throw new IllegalArgumentException("Number of absorption coefficients sets, " + n + ", does not match the number of layers, " + this.numberOfLayers); + int m = absorptionCoefficients.length; + if(this.wavelNumberSet && m!=this.numberOfWavelengths)throw new IllegalArgumentException("Number of absorption coefficients wavelengths, " + m + ", does not match the number of wavelengths already entered, " + this.numberOfWavelengths); + this.absorptionCoefficients = absorptionCoefficients; + this.absorbSet = true; + + if(this.refractSet && this.wavelSet){ + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + if(this.refractiveIndices[j][i].getImag()==0.0D)this.refractiveIndices[j][i].setImag(absorptionCoefficients[j][i]*this.wavelengths[j]/(4.0D*Math.PI)); + } + } + } + } + + // Enter absorption coefficients for a single layer [default = 0], range of wavelengths + public void setAbsorptionCoefficients(double[] absorptionCoefficients, int layerNumber){ + // set absorption coefficients array + int n = absorptionCoefficients.length; + if(this.wavelNumberSet){ + if(n!=this.numberOfWavelengths)throw new IllegalArgumentException("Layer " + layerNumber + ": number of absorption coefficients wavelengths, " + n + ", does not match the number of wavelengths already entered, " + this.numberOfWavelengths); + } + else{ + this.numberOfWavelengths = n; + this.refractiveIndices = Complex.twoDarray(this.numberOfWavelengths, this.numberOfLayers); + this.absorptionCoefficients = new double[this.numberOfWavelengths][this.numberOfLayers]; + } + layerNumber--; + this.absorptionCoefficients[layerNumber] = absorptionCoefficients; + for(int j=0; j<this.numberOfWavelengths; j++){ + if(this.refractiveIndices[j][layerNumber].getImag()==0.0D)this.refractiveIndices[j][layerNumber].setImag(absorptionCoefficients[j]*this.wavelengths[j]/(4.0D*Math.PI)); + } + this.absorbSet = true; + } + + // Enter absorption coefficients for a single layer [default = 0], single wavelength + public void setAbsorptionCoefficients(double absorptionCoefficient, int layerNumber){ + // set absorption coefficients array + if(this.wavelNumberSet){ + if(this.numberOfWavelengths!=1)throw new IllegalArgumentException("Layer " + layerNumber + ": number of absorption coefficients wavelengths, " + 1 + ", does not match the number of wavelengths already entered, " + this.numberOfWavelengths); + } + else{ + this.numberOfWavelengths = 1; + this.refractiveIndices = Complex.twoDarray(this.numberOfWavelengths, this.numberOfLayers); + this.absorptionCoefficients = new double[this.numberOfWavelengths][this.numberOfLayers]; + } + layerNumber--; + this.absorptionCoefficients[0][layerNumber] = absorptionCoefficient; + if(this.refractiveIndices[0][layerNumber].getImag()==0.0D)this.refractiveIndices[0][layerNumber].setImag(absorptionCoefficient*this.wavelengths[0]/(4.0D*Math.PI)); + + this.absorbSet = true; + } + + // Return absorption coefficients + public Object getAbsorptionCoefficients(){ + + double [][] absC = this.absorptionCoefficients; + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + absC[i][j] = 4.0D*Math.PI*this.wavelengths[j]*this.refractiveIndices[i][j].getImag(); + } + } + + if(this.numberOfWavelengths==1){ + double[] ret = absC[0]; + return (Object)ret; + } + else{ + return (Object)absC; + } + } + + // RELATIVE MAGNETIC PERMEABILITIES + + // Enter magnetic permeabilities as complex numbers [default values = 1.0] + public void setRelativeMagneticPermeabilities(Complex[][] relativeMagneticPermeabilities){ + int n = relativeMagneticPermeabilities[0].length; + if(n!=this.numberOfLayers)throw new IllegalArgumentException("Number of relative magnetic permeabilities, " + n + ", does not match the number of layers, " + this.numberOfLayers); + int m = relativeMagneticPermeabilities.length; + if(this.wavelNumberSet)if(m!=this.numberOfWavelengths)throw new IllegalArgumentException("Number of relative magnetic permeabilities associated wavelengths, " + m + ", does not match the number of wavelengths already entered, " + this.numberOfWavelengths); + this.relativeMagneticPermeabilities = relativeMagneticPermeabilities; + this.magneticSet = true; + + // calculate mean permeabilities + for(int i=0; i<this.numberOfLayers; i++){ + Complex sum = Complex.zero(); + for(int j=0; j<this.numberOfWavelengths; j++){ + sum.plusEquals(this.relativeMagneticPermeabilities[j][i]); + } + this.meanRelativeMagneticPermeabilities[i] = sum.over(this.numberOfWavelengths); + } + } + + // Enter magnetic permeabilities as real numbers [default values = 1.0] + public void relativeMagneticPermeabilities(double[][] relativeMagneticPermeabilities){ + int n = relativeMagneticPermeabilities[0].length; + if(n!=this.numberOfLayers)throw new IllegalArgumentException("Number of relative magnetic permeabilities, " + n + ", does not match the number of layers, " + this.numberOfLayers); + int m = relativeMagneticPermeabilities.length; + if(this.wavelNumberSet)if(m!=this.numberOfWavelengths)throw new IllegalArgumentException("Number of relative magnetic permeabilities associated wavelengths, " + m + ", does not match the number of wavelengths already entered, " + this.numberOfWavelengths); + this.relativeMagneticPermeabilities = Complex.twoDarray(m, n); + for(int i=0; i<this.numberOfLayers; i++){ + for(int j=0; j<this.numberOfWavelengths; j++){ + this.relativeMagneticPermeabilities[j][i].setReal(relativeMagneticPermeabilities[j][i]); + } + } + this.magneticSet = true; + + // calculate mean permeabilities + for(int i=0; i<this.numberOfLayers; i++){ + Complex sum = Complex.zero(); + for(int j=0; j<this.numberOfWavelengths; j++){ + sum.plusEquals(this.relativeMagneticPermeabilities[j][i]); + } + this.meanRelativeMagneticPermeabilities[i] = sum.over(this.numberOfWavelengths); + } + } + + // Enter magnetic permeabilities as a mean value for each layer, complex numbers [default values = 1.0] + public void setRelativeMagneticPermeabilities(Complex[] relativeMagneticPermeabilities){ + int n = relativeMagneticPermeabilities.length; + if(n!=this.numberOfLayers)throw new IllegalArgumentException("Number of relative magnetic permeabilities, " + n + ", does not match the number of layers, " + this.numberOfLayers); + this.meanRelativeMagneticPermeabilities = relativeMagneticPermeabilities; + this.meanMagneticUsed = true; + if(this.wavelNumberSet)for(int i=0; i<this.numberOfWavelengths; i++)this.relativeMagneticPermeabilities[i] = Complex.copy(relativeMagneticPermeabilities); + } + + // Enter magnetic permeabilities as a mean value for each layer, real numbers [default values = 1.0] + public void setRelativeMagneticPermeabilities(double[] relativeMagneticPermeabilities){ + int n = relativeMagneticPermeabilities.length; + if(n!=this.numberOfLayers)throw new IllegalArgumentException("Number of relative magnetic permeabilities, " + n + ", does not match the number of layers, " + this.numberOfLayers); + for(int i=0; i<n; i++)this.meanRelativeMagneticPermeabilities[i].setReal(relativeMagneticPermeabilities[i]); + this.meanMagneticUsed = true; + if(this.wavelNumberSet)for(int i=0; i<this.numberOfWavelengths; i++)this.relativeMagneticPermeabilities[i] = Complex.copy(this.meanRelativeMagneticPermeabilities); + + } + + // Enter magnetic permeabilities for a single layer, complex numbers [default values = 1.0] + public void setRelativeMagneticPermeabilities(Complex[] relativeMagneticPermeabilities, int layerNumber){ + int n = relativeMagneticPermeabilities.length; + if(this.wavelNumberSet){ + if(n!=this.numberOfWavelengths)throw new IllegalArgumentException("Layer " + layerNumber + ": number of relative magnetic permeabilities associated wavelengths, " + n + ", does not match the number of wavelengths already entered, " + this.numberOfWavelengths); + } + if(this.relativeMagneticPermeabilities==null)this.relativeMagneticPermeabilities = Complex.twoDarray(n, this.numberOfLayers); + this.relativeMagneticPermeabilities[layerNumber-1] = relativeMagneticPermeabilities; + Complex sum = Complex.zero(); + for(int i=0; i<n; i++)sum.plusEquals(this.relativeMagneticPermeabilities[i][layerNumber-1]); + this.meanRelativeMagneticPermeabilities[layerNumber-1] = sum.over(n); + } + + // Enter magnetic permeabilities for a single layer, real numbers [default values = 1.0] + public void setRelativeMagneticPermeabilities(double[] relativeMagneticPermeabilities, int layerNumber){ + int n = relativeMagneticPermeabilities.length; + if(this.wavelNumberSet){ + if(n!=this.numberOfWavelengths)throw new IllegalArgumentException("Layer " + layerNumber + ": number of relative magnetic permeabilities associated wavelengths, " + n + ", does not match the number of wavelengths already entered, " + this.numberOfWavelengths); + } + if(this.relativeMagneticPermeabilities==null)this.relativeMagneticPermeabilities = Complex.twoDarray(n, this.numberOfLayers); + for(int i=0; i<n; i++)this.relativeMagneticPermeabilities[i][layerNumber-1].setReal(relativeMagneticPermeabilities[i]); + Complex sum = Complex.zero(); + for(int i=0; i<n; i++)sum.plusEquals(this.relativeMagneticPermeabilities[i][layerNumber-1]); + this.meanRelativeMagneticPermeabilities[layerNumber-1] = sum.over(n); + } + + // Enter mean magnetic permeability for a single layer, complex number [default values = 1.0] + public void setRelativeMagneticPermeabilities(Complex relativeMagneticPermeability, int layerNumber){ + this.meanRelativeMagneticPermeabilities[layerNumber-1] = relativeMagneticPermeability; + this.meanMagneticUsed = true; + if(this.relativeMagneticPermeabilities!=null){ + int n = this.relativeMagneticPermeabilities[0].length; + for(int i=0; i<n;i++)this.relativeMagneticPermeabilities[i][layerNumber-1]=relativeMagneticPermeability; + } + } + + // Enter mean magnetic permeability for a single layer, real number [default values = 1.0] + public void setRelativeMagneticPermeabilities(double relativeMagneticPermeability, int layerNumber){ + this.meanRelativeMagneticPermeabilities[layerNumber-1].setReal(relativeMagneticPermeability); + this.meanMagneticUsed = true; + if(this.relativeMagneticPermeabilities!=null){ + int n = this.relativeMagneticPermeabilities[0].length; + for(int i=0; i<n;i++)this.relativeMagneticPermeabilities[i][layerNumber-1]=this.meanRelativeMagneticPermeabilities[layerNumber-1]; + } + } + + // Return relative magnetic permeabilities + public Object getRelativeMagneticPermeabilities(){ + if(this.numberOfWavelengths==1){ + Complex[] ret = this.relativeMagneticPermeabilities[0]; + return (Object)ret; + } + else{ + return (Object)this.relativeMagneticPermeabilities; + } + } + + // REFLECTIVITIES AND REFLECTION COEFFICIENTS + + // Return the reflectivities + public Object getReflectivities(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.reflectivities[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.reflectivities[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.reflectivities[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.reflectivities; + } + else{ + return null; + } + } + } + } + } + + // Return the TE mode reflection coefficients + public Object getTEreflectionCoefficients(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.reflectCoeffTE[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.reflectCoeffTE[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + Complex[] ret = Complex.oneDarray(this.numberOfWavelengths); + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.reflectCoeffTE[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.reflectCoeffTE; + } + else{ + return null; + } + } + } + } + } + + // Return the TM mode reflection coefficients + public Object getTMreflectionCoefficients(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.reflectCoeffTM[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.reflectCoeffTM[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + Complex[] ret = Complex.oneDarray(this.numberOfWavelengths); + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.reflectCoeffTM[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.reflectCoeffTM; + } + else{ + return null; + } + } + } + } + } + + // TRANSMISSIVITIES, TRANSMISSION COEFFICIENTS AND TRANSMISSION ANGLES + + // Return the transmissivities + public Object getTransmissivities(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.transmissivities[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.transmissivities[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.transmissivities[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.transmissivities; + } + else{ + return null; + } + } + } + } + } + + // Return the power loss on transmission as decibels + public Object getPowerLoss(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.powerLosses[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.powerLosses[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.powerLosses[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.powerLosses; + } + else{ + return null; + } + } + } + } + } + + // Return the angle of transmitted beam with respect to normal (radians) + public Object getTransmissionAnglesInRadians(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.transmitAnglesRad[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.transmitAnglesRad[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.transmitAnglesRad[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.transmitAnglesRad; + } + else{ + return null; + } + } + } + } + } + + // Return the angle of transmitted beam with respect to normal (degrees) + public Object getTransmissionAnglesInDegrees(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.transmitAnglesDeg[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.transmitAnglesDeg[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.transmitAnglesDeg[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.transmitAnglesDeg; + } + else{ + return null; + } + } + } + } + } + + // Return the TE mode transmission coefficients + public Object getTEtransmissionCoefficients(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.transmitCoeffTE[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.transmitCoeffTE[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + Complex[] ret = Complex.oneDarray(this.numberOfWavelengths); + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.transmitCoeffTE[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.transmitCoeffTE; + } + else{ + return null; + } + } + } + } + } + + // Return the TM mode transmission coefficients + public Object getTMtransmissionCoefficients(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.transmitCoeffTM[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.transmitCoeffTM[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + Complex[] ret = Complex.oneDarray(this.numberOfWavelengths); + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.transmitCoeffTM[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.transmitCoeffTM; + } + else{ + return null; + } + } + } + } + } + + + // PHASE SHIFTS + + // Return the phase shifts on reflection (TE mode)in degrees + public Object getTEreflectionPhaseShiftDeg(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.reflectPhaseShiftDegTE[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.reflectPhaseShiftDegTE[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.reflectPhaseShiftDegTE[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.reflectPhaseShiftDegTE; + } + else{ + return null; + } + } + } + } + } + + // Return the phase shifts on reflection (TE mode)in radians + public Object getTEreflectionPhaseShiftRad(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.reflectPhaseShiftRadTE[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.reflectPhaseShiftRadTE[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.reflectPhaseShiftRadTE[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.reflectPhaseShiftRadTE; + } + else{ + return null; + } + } + } + } + } + + // Return the phase shifts on reflection (TM mode)in degrees + public Object getTMreflectionPhaseShiftDeg(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.reflectPhaseShiftDegTM[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.reflectPhaseShiftDegTM[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.reflectPhaseShiftDegTM[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.reflectPhaseShiftDegTM; + } + else{ + return null; + } + } + } + } + } + + // Return the phase shifts on reflection (TM mode)in radians + public Object getTMreflectionPhaseShiftRad(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.reflectPhaseShiftRadTM[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.reflectPhaseShiftRadTM[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.reflectPhaseShiftRadTM[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.reflectPhaseShiftRadTM; + } + else{ + return null; + } + } + } + } + } + + // Return the phase shifts on transmission (TE mode)in degrees + public Object getTEtransmissionPhaseShiftDeg(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.transmitPhaseShiftDegTE[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.transmitPhaseShiftDegTE[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.transmitPhaseShiftDegTE[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.transmitPhaseShiftDegTE; + } + else{ + return null; + } + } + } + } + } + + // Return the phase shifts on transmission (TE mode)in radians + public Object getTEtransmissionPhaseShiftRad(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.transmitPhaseShiftRadTE[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.transmitPhaseShiftRadTE[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.transmitPhaseShiftRadTE[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.transmitPhaseShiftRadTE; + } + else{ + return null; + } + } + } + } + } + + // Return the phase shifts on transmission (TM mode)in degrees + public Object getTMtransmissionPhaseShiftDeg(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.transmitPhaseShiftDegTM[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.transmitPhaseShiftDegTM[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.transmitPhaseShiftDegTM[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.transmitPhaseShiftDegTM; + } + else{ + return null; + } + } + } + } + } + + // Return the phase shifts on transmission (TM mode)in radians + public Object getTMtransmissionPhaseShiftRad(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.transmitPhaseShiftRadTM[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.transmitPhaseShiftRadTM[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.transmitPhaseShiftRadTM[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.transmitPhaseShiftRadTM; + } + else{ + return null; + } + } + } + } + } + + + + // EVANESCENT FIELDS + + // Return the integrated evanescent fields + public Object getEvanescentFields(double fieldDistance){ + this.fieldDistance = fieldDistance; + return getEvanescentFields(); + } + + // Return the integrated evanescent fields - default field depth (POSITIVE_INFINITY) + public Object getEvanescentFields(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.evanescentFields[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.evanescentFields[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.evanescentFields[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.evanescentFields; + } + else{ + return null; + } + } + } + } + } + + // Return the evanescent field penetration depths + public Object getPenetrationDepths(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.penetrationDepths[0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.penetrationDepths[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + double[] ret = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)ret[i] = this.penetrationDepths[i][0]; + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.penetrationDepths; + } + else{ + return null; + } + } + } + } + } + + // WAVE VECTORS ko, k, kx and kz + + // Return the ko vectors + public Object getKoVectors(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.koVector[0][0][0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.koVector[0][0][0]; + } + else{ + if(this.wavelengthReflectCalculated){ + Complex[] ret = Complex.oneDarray(this.numberOfWavelengths); + for(int i=0; i<this.numberOfWavelengths; i++){ + ret[i] = this.koVector[i][0][0]; + } + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + Complex[] ret = Complex.oneDarray(this.numberOfWavelengths); + for(int i=0; i<this.numberOfWavelengths; i++){ + ret[i] = this.koVector[i][0][0]; + } + return (Object)ret; + } + else{ + return null; + } + } + } + } + } + + // Return the kz vectors + public Object getKzVectors(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.kzVector[0][0][0]; + } + else{ + if(this.angularReflectCalculated){ + Complex[] ret = Complex.oneDarray(this.numberOfIncidentAngles); + for(int i=0; i<this.numberOfIncidentAngles; i++){ + ret[i] = this.kzVector[0][i][0]; + } + return (Object)ret; + } + else{ + if(this.wavelengthReflectCalculated){ + Complex[] ret = Complex.oneDarray(this.numberOfWavelengths); + for(int i=0; i<this.numberOfWavelengths; i++){ + ret[i] = this.kzVector[i][0][0]; + } + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + Complex[][] ret = Complex.twoDarray(this.numberOfWavelengths, this.numberOfIncidentAngles); + for(int i=0; i<this.numberOfWavelengths; i++){ + for(int j=0; j<this.numberOfIncidentAngles; j++){ + ret[i][j] = this.kzVector[i][j][0]; + } + } + return (Object)ret; + } + else{ + return null; + } + } + } + } + } + + // Return the k vectors + public Object getKvectors(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.kVector[0][0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.kVector[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + Complex[][] ret = Complex.twoDarray(this.numberOfWavelengths, this.numberOfLayers); + for(int i=0; i<this.numberOfWavelengths; i++){ + for(int j=0; i<this.numberOfLayers; i++){ + ret[i][j] = this.kVector[i][0][j]; + } + } + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + Complex[][] ret = Complex.twoDarray(this.numberOfWavelengths, this.numberOfLayers); + for(int i=0; i<this.numberOfWavelengths; i++){ + for(int j=0; i<this.numberOfLayers; i++){ + ret[i][j] = this.kVector[i][0][j]; + } + } + return (Object)ret; + } + else{ + return null; + } + } + } + } + } + + // Return the kx vectors + public Object getKxVectors(){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated){ + return (Object)this.kxVector[0][0]; + } + else{ + if(this.angularReflectCalculated){ + return (Object)this.kxVector[0]; + } + else{ + if(this.wavelengthReflectCalculated){ + Complex[][] ret = Complex.twoDarray(this.numberOfWavelengths, this.numberOfLayers); + for(int i=0; i<this.numberOfWavelengths; i++){ + for(int j=0; i<this.numberOfLayers; i++){ + ret[i][j] = this.kxVector[i][0][j]; + } + } + return (Object)ret; + } + else{ + if(this.wavelengthAndAngularReflectCalculated){ + return (Object)this.kxVector; + } + else{ + return null; + } + } + } + } + } + + // METHODS THAT PLOT THE SIMULATIONS + + // Reset wavelength axis to frequency axis + public void resetPlotAxisAsFrequency(){ + this.wavelengthAxisOption = 2; + } + + // Reset wavelength axis to frequency axis + public void resetPlotAxisAsRadians(){ + this.wavelengthAxisOption = 3; + } + + // Reset wavelength axis to frequency axis + public void resetPlotAxisAsWavelength(){ + this.wavelengthAxisOption = 1; + } + + // Calculation and plotting of the reflectivities for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotReflectivities(){ + String legend = "Polarisation mode: " + this.mode; + this.plotReflectivities(legend); + } + + // Calculation and plotting of the reflectivities for a single or multiple wavelengths and a range of incident angles entered + public void plotReflectivities(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + + String graphLegendExtra = " Reflectivities"; + String yLegend = "Reflectivity"; + String yUnits = " "; + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) this.reflectivities); + } + + // Calculation and plotting of the transmissivities for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotTransmissivities(){ + String legend = "Polarisation mode: " + this.mode; + this.plotTransmissivities(legend); + } + + // Calculation and plotting of the transmissivities for a single or multiple wavelengths and a range of incident angles entered + public void plotTransmissivities(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + String graphLegendExtra = " Transmissivities"; + String yLegend = "Transmissivity"; + String yUnits = " "; + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) this.transmissivities); + } + + // Calculation and plotting of the power losses on transmission for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotPowerLosses(){ + String legend = "Polarisation mode: " + this.mode; + this.plotPowerLosses(legend); + } + + // Calculation and plotting of the power losses on transmission for a single or multiple wavelengths and a range of incident angles entered + public void plotPowerLosses(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + String graphLegendExtra = " Power Losses in decibels relative to an incident power of 1 mW"; + String yLegend = "Power Losses"; + String yUnits = "dBm"; + + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) this.powerLosses); + } + + // Calculation and plotting of the transmission angles for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotTransmissionAngles(){ + String legend = "Polarisation mode: " + this.mode; + this.plotTransmissionAngles(legend); + } + + // Calculation and plotting of the transmission angles for a single or multiple wavelengths and a range of incident angles entered + public void plotTransmissionAngles(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + String graphLegendExtra = " Transmission angles (degrees)"; + String yLegend = "Transmission angle"; + String yUnits = "degrees"; + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) this.transmitAnglesDeg); + } + + // Calculation and plotting of the absolute values of TE reflection coefficients for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotAbsTEreflectionCoefficients(){ + String legend = "Polarisation mode: " + this.mode; + this.plotAbsTEreflectionCoefficients(legend); + } + + // Calculation and plotting of the absolute values of TE reflection coefficients for a single or multiple wavelengths and a range of incident angles entered + public void plotAbsTEreflectionCoefficients(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + if(teFraction==0.0D){ + System.out.println("No TE transmission coefficient plot displayed as no light in the TE mode"); + } + else{ + double[][] absTEr = new double[numberOfWavelengths][this.numberOfIncidentAngles]; + for(int i=0; i<this.numberOfWavelengths; i++){ + for(int j=0; j<this.numberOfIncidentAngles; j++){ + absTEr[i][j] = this.reflectCoeffTE[i][j].abs(); + } + } + + String graphLegendExtra = " Absolute values of the TE reflection coefficients"; + String yLegend = "|TE Reflection Coefficient|"; + String yUnits = " "; + + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) absTEr); + } + } + + // Calculation and plotting of the absolute values of TM reflection coefficients for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotAbsTMreflectionCoefficients(){ + String legend = "Polarisation mode: " + this.mode; + this.plotAbsTMreflectionCoefficients(legend); + } + + // Calculation and plotting of the absolute values of TM reflection coefficients for a single or multiple wavelengths and a range of incident angles entered + public void plotAbsTMreflectionCoefficients(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + if(tmFraction==0.0D){ + System.out.println("No TM transmission coefficient plot displayed as no light in the TM mode"); + } + else{ + double[][] absTMr = new double[numberOfWavelengths][this.numberOfIncidentAngles]; + for(int i=0; i<this.numberOfWavelengths; i++){ + for(int j=0; j<this.numberOfIncidentAngles; j++){ + absTMr[i][j] = this.reflectCoeffTM[i][j].abs(); + } + } + + String graphLegendExtra = " Absolute values of the TM reflection coefficients"; + String yLegend = "|TM Reflection Coefficient|"; + String yUnits = " "; + + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) absTMr); + } + } + + // Calculation and plotting of the absolute values of TE transmission coefficients for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotAbsTEtransmissionCoefficients(){ + String legend = "Polarisation mode: " + this.mode; + this.plotAbsTEtransmissionCoefficients(legend); + } + + // Calculation and plotting of the absolute values of TE transmission coefficients for a single or multiple wavelengths and a range of incident angles entered + public void plotAbsTEtransmissionCoefficients(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + if(teFraction==0.0D){ + System.out.println("No TE transmission coefficient plot displayed as no light in the TE mode"); + } + else{ + double[][] absTEt = new double[numberOfWavelengths][this.numberOfIncidentAngles]; + for(int i=0; i<this.numberOfWavelengths; i++){ + for(int j=0; j<this.numberOfIncidentAngles; j++){ + absTEt[i][j] = this.transmitCoeffTE[i][j].abs(); + } + } + + String graphLegendExtra = " Absolute values of the TE transmission coefficients"; + String yLegend = "|TE Transmission Coefficient|"; + String yUnits = " "; + + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) absTEt); + } + } + + // Calculation and plotting of the absolute values of TM transmission coefficients for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotAbsTMtransmissionCoefficients(){ + String legend = "Polarisation mode: " + this.mode; + this.plotAbsTMtransmissionCoefficients(legend); + } + + // Calculation and plotting of the absolute values of TM transmission coefficients for a single or multiple wavelengths and a range of incident angles entered + public void plotAbsTMtransmissionCoefficients(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + if(tmFraction==0.0D){ + System.out.println("No TM transmission coefficient plot displayed as no light in the TM mode"); + } + else{ + double[][] absTMt = new double[numberOfWavelengths][this.numberOfIncidentAngles]; + for(int i=0; i<this.numberOfWavelengths; i++){ + for(int j=0; j<this.numberOfIncidentAngles; j++){ + absTMt[i][j] = this.transmitCoeffTM[i][j].abs(); + } + } + + String graphLegendExtra = " Absolute values of the TM transmission coefficients"; + String yLegend = "|TM Transmission Coefficient|"; + String yUnits = " "; + + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) absTMt); + } + } + + // Calculation and plotting of the integrated evanescent field for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotEvanescentFields(){ + String legend = "Polarisation mode: " + this.mode; + this.plotEvanescentFields(legend); + } + + // Calculation and plotting of the integrated evanescent field for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided, resetting distnce over which field is integrated + public void plotEvanescentFields(double distanceIntoField){ + this.fieldDistance = fieldDistance; + String legend = "Polarisation mode: " + this.mode; + this.plotEvanescentFields(legend); + } + + // Calculation and plotting of the integrated evanescent fields for a single or multiple wavelengths and a range of incident angles entered + // Resetting distnce over which field is integrated + public void plotEvanescentFields(double fieldDistance, String legend){ + this.fieldDistance = fieldDistance; + this.plotEvanescentFields(legend); + } + + // Calculation and plotting of the integrated evanescent fields for a single or multiple wavelengths and a range of incident angles entered + public void plotEvanescentFields(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + String graphLegendExtra = " Integrated Evanescent Field Intensities to a depth of " + this.fieldDistance + " metres"; + String yLegend = "Evanescent Field intensity"; + String yUnits = " "; + + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) this.evanescentFields); + } + + // Calculation and plotting of the evanescent field penetration depths for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotPenetrationDepths(){ + String legend = "Polarisation mode: " + this.mode; + this.plotPenetrationDepths(legend); + } + + // Calculation and plotting of the evanescent field penetration depths for a single or multiple wavelengths and a range of incident angles entered + public void plotPenetrationDepths(String graphLegend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + String graphLegendExtra = " Evanescent Field Penetration Depths"; + String yLegend = "Penetration Depth"; + String yUnits = "metres"; + + plotSimulation(graphLegend, graphLegendExtra, yLegend, yUnits, (Object) this.penetrationDepths); + } + + // Calculation and plotting of the phase shift on reflection (TE mode), in degrees, for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotTEreflectionPhaseShiftDeg(){ + String legend = "Polarisation mode: " + this.mode; + this.plotTEreflectionPhaseShiftDeg(legend); + } + + // Calculation and plotting of the phase shift on reflection (TE mode), in degrees, for a single or multiple wavelengths and a range of incident angles entered + public void plotTEreflectionPhaseShiftDeg(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + if(teFraction==0.0D){ + System.out.println("No TE phase shift plot displayed as no light in the TE mode"); + } + else{ + String graphLegendExtra = " Phase Shift on Reflection (TE mode)"; + String yLegend = "Phase shift"; + String yUnits = "degrees "; + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) this.reflectPhaseShiftDegTE); + } + } + + // Calculation and plotting of the phase shift on reflection (TM mode), in degrees, for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotTMreflectionPhaseShiftDeg(){ + String legend = "Polarisation mode: " + this.mode; + this.plotTMreflectionPhaseShiftDeg(legend); + } + + // Calculation and plotting of the phase shift on reflection (TM mode), in degrees, for a single or multiple wavelengths and a range of incident angles entered + public void plotTMreflectionPhaseShiftDeg(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + if(tmFraction==0.0D){ + System.out.println("No TM phase shift plot displayed as no light in the TM mode"); + } + else{ + String graphLegendExtra = " Phase Shift on Reflection (TM mode)"; + String yLegend = "Phase shift"; + String yUnits = "degrees "; + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) this.reflectPhaseShiftDegTM); + } + } + + // Calculation and plotting of the phase shift on reflection (TE mode), in radians, for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotTEreflectionPhaseShiftRad(){ + String legend = "Polarisation mode: " + this.mode; + this.plotTEreflectionPhaseShiftRad(legend); + } + + // Calculation and plotting of the phase shift on reflection (TE mode), in radians, for a single or multiple wavelengths and a range of incident angles entered + public void plotTEreflectionPhaseShiftRad(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + if(teFraction==0.0D){ + System.out.println("No TE phase shift plot displayed as no light in the TE mode"); + } + else{ + String graphLegendExtra = " Phase Shift on Reflection (TE mode)"; + String yLegend = "Phase shift"; + String yUnits = "radians "; + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) this.reflectPhaseShiftRadTE); + } + } + + + // Calculation and plotting of the phase shift on reflection (TM mode), in radians, for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotTMreflectionPhaseShiftRad(){ + String legend = "Polarisation mode: " + this.mode; + this.plotTMreflectionPhaseShiftRad(legend); + } + + // Calculation and plotting of the phase shift on reflection (TM mode), in radians, for a single or multiple wavelengths and a range of incident angles entered + public void plotTMreflectionPhaseShiftRad(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + if(tmFraction==0.0D){ + System.out.println("No TM phase shift plot displayed as no light in the TM mode"); + } + else{ + String graphLegendExtra = " Phase Shift on Reflection (TM mode)"; + String yLegend = "Phase shift"; + String yUnits = "radians "; + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) this.reflectPhaseShiftRadTM); + } + } + + // Calculation and plotting of the phase shift on transmission (TE mode), in degrees, for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotTEtransmissionPhaseShiftDeg(){ + String legend = "Polarisation mode: " + this.mode; + this.plotTEtransmissionPhaseShiftDeg(legend); + } + + // Calculation and plotting of the phase shift on transmission (TE mode), in degrees, for a single or multiple wavelengths and a range of incident angles entered + public void plotTEtransmissionPhaseShiftDeg(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + if(teFraction==0.0D){ + System.out.println("No TE phase shift plot displayed as no light in the TE mode"); + } + else{ + String graphLegendExtra = " Phase Shift on Transmission (TE mode)"; + String yLegend = "Phase shift"; + String yUnits = "degrees "; + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) this.transmitPhaseShiftDegTE); + } + } + + // Calculation and plotting of the phase shift on transmission (TM mode), in degrees, for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotTMtransmissionPhaseShiftDeg(){ + String legend = "Polarisation mode: " + this.mode; + this.plotTMtransmissionPhaseShiftDeg(legend); + } + + // Calculation and plotting of the phase shift on transmission (TM mode), in degrees, for a single or multiple wavelengths and a range of incident angles entered + public void plotTMtransmissionPhaseShiftDeg(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + if(tmFraction==0.0D){ + System.out.println("No TM phase shift plot displayed as no light in the TM mode"); + } + else{ + String graphLegendExtra = " Phase Shift on Transmission (TM mode)"; + String yLegend = "Phase shift"; + String yUnits = "degrees "; + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) this.transmitPhaseShiftDegTM); + } + } + + // Calculation and plotting of the phase shift on transmission (TE mode), in radians, for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotTEtransmissionPhaseShiftRad(){ + String legend = "Polarisation mode: " + this.mode; + this.plotTEtransmissionPhaseShiftRad(legend); + } + + // Calculation and plotting of the phase shift on transmission (TE mode), in radians, for a single or multiple wavelengths and a range of incident angles entered + public void plotTEtransmissionPhaseShiftRad(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + if(teFraction==0.0D){ + System.out.println("No TE phase shift plot displayed as no light in the TE mode"); + } + else{ + String graphLegendExtra = " Phase Shift on Transmission (TE mode)"; + String yLegend = "Phase shift"; + String yUnits = "radians "; + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) this.transmitPhaseShiftRadTE); + } + } + + // Calculation and plotting of the phase shift on transmission (TM mode), in radians, for a single or multiple wavelengths and a range of incident angles entered + // No user legend provided + public void plotTMtransmissionPhaseShiftRad(){ + String legend = "Polarisation mode: " + this.mode; + this.plotTMtransmissionPhaseShiftRad(legend); + } + + // Calculation and plotting of the phase shift on transmission (TM mode), in radians, for a single or multiple wavelengths and a range of incident angles entered + public void plotTMtransmissionPhaseShiftRad(String legend){ + this.checkWhichCalculation(); + if(this.singleReflectCalculated)throw new IllegalArgumentException("Plot methods require more than one data point"); + + if(tmFraction==0.0D){ + System.out.println("No TM phase shift plot displayed as no light in the TM mode"); + } + else{ + String graphLegendExtra = " Phase Shift on Transmission (TM mode)"; + String yLegend = "Phase shift"; + String yUnits = "radians "; + plotSimulation(legend, graphLegendExtra, yLegend, yUnits, (Object) this.transmitPhaseShiftRadTM); + } + } + + // Plotting of the simulation curves + public void plotSimulation(String graphLegend, String graphLegendExtra, String yLegend, String yUnits, Object yValuesObject){ + + // Calculate yValuesObject internal array dimensions and fill yValues array + Object internalArray = yValuesObject; + int nCurves = 1; + while(!((internalArray = Array.get(internalArray, 0)) instanceof Double))nCurves++; + double[][] yValues = new double[nCurves][]; + if(nCurves==1){ + double[] temp = (double[])yValuesObject; + yValues[0] = temp; + } + else{ + yValues = (double[][])yValuesObject; + } + int nPoints = yValues.length; + + int[] pointOptions = null; + double[][] plotData = null; + String xLegend = null; + String xUnits = null; + + if(this.angularReflectCalculated){ + pointOptions = new int[1]; + pointOptions[0] = 1; + plotData = new double[2][nPoints]; + plotData[0] = this.incidentAngleDeg; + plotData[1] = yValues[0]; + xLegend = "Incident Angle"; + xUnits = "degrees"; + } + + if(this.wavelengthReflectCalculated){ + pointOptions = new int[1]; + pointOptions[0] = 1; + plotData = new double[2][nPoints]; + plotData[0] = this.wavelengths; + double[] temp = new double[this.numberOfWavelengths]; + for(int i=0; i<this.numberOfWavelengths; i++)temp[i]=yValues[i][0]; + switch(wavelengthAxisOption){ + case 1: plotData[0] = this.wavelengths; + plotData[1] = temp; + xLegend = "Wavelength"; + xUnits = "metres"; + break; + case 2: plotData[0] = this.frequencies; + for(int i=0; i<this.numberOfWavelengths; i++)plotData[1][this.numberOfWavelengths-1-i] = temp[i]; + xLegend = "Frequency"; + xUnits = "Hz"; + break; + case 3: plotData[0] = this.omega; + for(int i=0; i<this.numberOfWavelengths; i++)plotData[1][this.numberOfWavelengths-1-i] = temp[i]; + xLegend = "Radial Frequency"; + xUnits = "radians"; + break; + } + } + + if(this.wavelengthAndAngularReflectCalculated){ + pointOptions = new int[nCurves]; + plotData = new double[2*nCurves][nPoints]; + for(int i=0; i<nCurves; i++){ + pointOptions[i] = i+1; + plotData[2*i] = this.incidentAngleDeg; + plotData[2*i+1] = yValues[i]; + } + xLegend = "Incident Angle"; + xUnits = "degrees"; + } + + PlotGraph pg = new PlotGraph(plotData); + pg.setGraphTitle("Class Reflectivity: Simulation Plot - " + graphLegendExtra); + pg.setGraphTitle2(graphLegend); + pg.setXaxisLegend(xLegend); + pg.setYaxisLegend(yLegend); + pg.setXaxisUnitsName(xUnits); + if(!yUnits.equals(" "))pg.setYaxisUnitsName(yUnits); + pg.setLine(3); + pg.setPoint(pointOptions); + pg.plot(); + } + + + // CORE CALCULATION METHODS + + // Check whether reflectivity calculation has been performed + // and perform calculation if not + public void checkWhichCalculation(){ + boolean test=false; + if(this.singleReflectCalculated)test=true; + if(this.angularReflectCalculated)test=true; + if(this.wavelengthReflectCalculated)test=true; + if(this.wavelengthAndAngularReflectCalculated)test=true; + + if(test){ + if(this.fieldDistance!=Double.POSITIVE_INFINITY && !this.fieldIntensityCalc){ + int nkouter = this.numberOfLayers - 1; + double integratedEvanescentField = 0.0D; + for(int i=0; i<this.numberOfWavelengths; i++){ + for(int j=0; j<this.numberOfIncidentAngles; j++){ + if(this.kxVector[i][j][nkouter].getReal()==0.0D){ + double penetrationDepth = 1.0D/this.kxVector[i][j][nkouter].getImag(); + integratedEvanescentField += this.teFraction*Fmath.square(this.transmitCoeffTE[i][j].abs())*(1.0D - Math.exp(-2.0D*this.fieldDistance/penetrationDepth))*penetrationDepth/2.0D; + double refrTerm = this.refractiveIndices[i][0].getReal()/this.refractiveIndices[i][j].getReal(); + double magnTerm = Math.sqrt(this.relativeMagneticPermeabilities[i][nkouter].getReal()/this.relativeMagneticPermeabilities[i][0].getReal()); + integratedEvanescentField += this.teFraction*Fmath.square(this.transmitCoeffTM[i][j].abs())*magnTerm*refrTerm*(1.0D - Math.exp(-2.0D*this.fieldDistance/penetrationDepth))*penetrationDepth/2.0D; + } + } + } + this.fieldIntensityCalc = true; + } + } + else{ + if(this.numberOfIncidentAngles==0)throw new IllegalArgumentException("No incident angle/s has/have been entered"); + if(this.numberOfWavelengths==0)throw new IllegalArgumentException("No wavelength/s has/have been entered"); + + if(this.numberOfWavelengths>1)this.sortWavelengths(); + + // Calculate ko, k, kx and kz vectors + // redundant arrays included for ease of programming + this.koVector = Complex.threeDarray(this.numberOfWavelengths, this.numberOfIncidentAngles, this.numberOfLayers); + this.kzVector = Complex.threeDarray(this.numberOfWavelengths, this.numberOfIncidentAngles, this.numberOfLayers); + this.kVector = Complex.threeDarray(this.numberOfWavelengths, this.numberOfIncidentAngles, this.numberOfLayers); + this.kxVector = Complex.threeDarray(this.numberOfWavelengths, this.numberOfIncidentAngles, this.numberOfLayers); + + for(int i=0; i<this.numberOfWavelengths; i++){ + for(int j=0; j<this.numberOfIncidentAngles; j++){ + for(int k=0; k<this.numberOfLayers; k++){ + // Calculate ko values + this.koVector[i][j][k].reset(2.0D*Math.PI/this.wavelengths[i], 0.0D); + + // Calculate k vector + this.kVector[i][j][k] = this.koVector[i][j][k].times(this.refractiveIndices[i][k]).times(Complex.sqrt(this.relativeMagneticPermeabilities[i][k])); + + // Calculate kz vector + this.kzVector[i][j][k] = this.koVector[i][j][k].times(this.refractiveIndices[i][0]).times(Complex.sqrt(this.relativeMagneticPermeabilities[i][0])); + this.kzVector[i][j][k] = this.kzVector[i][j][k].times(Math.sin(this.incidentAngleRad[j])); + + // Calculate kx vector + this.kxVector[i][j][k] = (Complex.square(this.kVector[i][j][k])).minus(Complex.square(this.kzVector[i][j][k])); + this.kxVector[i][j][k] = Complex.sqrt(this.kxVector[i][j][k]); + // if(this.kxVector[i][j][k].getImag()>0.0D)this.kxVector[i][j][k] = this.kxVector[i][j][k].times(Complex.minusOne()); + + } + } + } + + // Arrays for calculated parameters + this.reflectivities = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + this.transmissivities = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + this.powerLosses = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + this.reflectCoeffTE = Complex.twoDarray(this.numberOfWavelengths, this.numberOfIncidentAngles); + this.reflectCoeffTM = Complex.twoDarray(this.numberOfWavelengths, this.numberOfIncidentAngles); + this.transmitCoeffTE = Complex.twoDarray(this.numberOfWavelengths, this.numberOfIncidentAngles); + this.transmitCoeffTM = Complex.twoDarray(this.numberOfWavelengths, this.numberOfIncidentAngles); + this.evanescentFields = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + this.penetrationDepths = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + this.transmitAnglesRad = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + this.transmitAnglesDeg = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + this.reflectPhaseShiftRadTE = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + this.reflectPhaseShiftRadTM = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + this.reflectPhaseShiftDegTE = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + this.reflectPhaseShiftDegTM = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + this.transmitPhaseShiftRadTE = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + this.transmitPhaseShiftRadTM = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + this.transmitPhaseShiftDegTE = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + this.transmitPhaseShiftDegTM = new double[this.numberOfWavelengths][this.numberOfIncidentAngles]; + + // Perform scan over angles and wavelengths + this.scan(); + } + } + + // Calculation of the reflection coefficient for a single or multiple wavelengths and a single or range of incident angles entered + public void scan(){ + if(!this.wavelSet)throw new IllegalArgumentException("No wavelength has been entered"); + if(!this.refractSet)throw new IllegalArgumentException("No, or not all, refractive indices have been entered"); + if(!this.thickSet)throw new IllegalArgumentException("No, or not all, layer thicknesses have been entered"); + if(!this.incidentAngleSet)throw new IllegalArgumentException("No incident angle has been entered"); + if(!this.modeSet)throw new IllegalArgumentException("No polaristaion mode (TE, TM, unpolarised or mixed[angle to be entered]) has been entered"); + + this.singleReflectCalculated = false; + this.angularReflectCalculated = false; + this.wavelengthReflectCalculated = false; + this.wavelengthAndAngularReflectCalculated = false; + + for(int i=0; i<this.numberOfWavelengths; i++){ + for(int j=0; j<this.numberOfIncidentAngles; j++){ + this.calcReflectivity(i, j); + } + } + + if(this.numberOfWavelengths==1){ + if(this.numberOfIncidentAngles==1){ + this.singleReflectCalculated = true; // = true when only a single angular relectivity has been calculated + } + else{ + this.angularReflectCalculated = true; // = true when an angular relectivity scan has been calculated + } + } + else{ + if(this.numberOfIncidentAngles==1){ + this.wavelengthReflectCalculated = true; // = true when a wavelength relectivity scan has been calculated + } + else{ + this.wavelengthAndAngularReflectCalculated = true; // = true when angular for each wavelength relectivity scan has been calculated + } + } + } + + // Calculate the reflectivity at a given incident angle and wavelength + public void calcReflectivity(int wavelengthIndex, int angleIndex){ + + double[] ret1 = new double[6]; + + if(this.teFraction>0.0D){ + ret1 = this.calcTEreflectivity(wavelengthIndex, angleIndex); + } + if(this.tmFraction>0.0D){ + double[] ret2 = this.calcTMreflectivity(wavelengthIndex, angleIndex); + ret1[0] = this.teFraction*ret1[0] + this.tmFraction*ret2[0]; + ret1[1] = this.teFraction*ret1[1] + this.tmFraction*ret2[1]; + ret1[2] = this.teFraction*ret1[2] + this.tmFraction*ret2[2]; + ret1[3] = this.teFraction*ret1[3] + this.tmFraction*ret2[3]; + ret1[4] = this.teFraction*ret1[4] + this.tmFraction*ret2[4]; + ret1[5] = this.teFraction*ret1[5] + this.tmFraction*ret2[5]; + } + + this.reflectivities[wavelengthIndex][angleIndex] = ret1[0]; + this.transmissivities[wavelengthIndex][angleIndex]= ret1[1]; + this.transmitAnglesRad[wavelengthIndex][angleIndex] = ret1[2]; + this.transmitAnglesDeg[wavelengthIndex][angleIndex] = Math.toDegrees(ret1[2]); + this.evanescentFields[wavelengthIndex][angleIndex] = ret1[3]; + this.penetrationDepths[wavelengthIndex][angleIndex] = ret1[4]; + this.powerLosses[wavelengthIndex][angleIndex] = ret1[5]; + + } + + // Calculate the reflectivities for the TE mode + public double[] calcTEreflectivity(int wavelengthIndex, int angleIndex){ + + Complex tempc1 = Complex.zero(); // temporary variable for calculations + Complex tempc2 = Complex.zero(); // temporary variable for calculations + Complex tempc3 = Complex.zero(); // temporary variable for calculations + Complex tempc4 = Complex.zero(); // temporary variable for calculations + + double penetrationDepth = 0.0D; + + if(this.numberOfLayers==2){ + tempc1 = this.relativeMagneticPermeabilities[wavelengthIndex][1].times(this.kxVector[wavelengthIndex][angleIndex][0]); + tempc2 = this.relativeMagneticPermeabilities[wavelengthIndex][0].times(this.kxVector[wavelengthIndex][angleIndex][1]); + tempc3 = tempc1.minus(tempc2); + tempc4 = tempc1.plus(tempc2); + this.reflectCoeffTE[wavelengthIndex][angleIndex] = tempc3.over(tempc4); + + tempc3 = tempc1.times(2.0D); + this.transmitCoeffTE[wavelengthIndex][angleIndex] = tempc3.over(tempc4); + } + else{ + // Create instance of Matrix Mi + ComplexMatrix mati = new ComplexMatrix(2, 2); + + // Create instance of Complex array Mi + Complex[][] matic = Complex.twoDarray(2, 2); + + // Calculate cos(theta[1]), beta[1], cos[beta[1]], sin[beta[1]], p[1] + Complex costheta = this.kxVector[wavelengthIndex][angleIndex][1].over(this.kVector[wavelengthIndex][angleIndex][1]); + Complex pTerm = (this.refractiveIndices[wavelengthIndex][1].over(this.impedance)).over(Complex.sqrt(this.relativeMagneticPermeabilities[wavelengthIndex][1])); + pTerm = pTerm.times(costheta); + Complex beta = this.kxVector[wavelengthIndex][angleIndex][1].times(this.thicknesses[1]); + matic[0][0] = Complex.cos(beta); + matic[1][1] = matic[0][0]; + tempc1 = Complex.sin(beta); + tempc1 = tempc1.times(Complex.minusJay()); + matic[0][1] = tempc1.over(pTerm); + matic[1][0] = tempc1.times(pTerm); + + if(this.numberOfLayers>3){ + + // Create instance of Matrix M + ComplexMatrix mat = new ComplexMatrix(Complex.copy(matic)); + + for(int i=2; i<this.numberOfLayers-1;i++){ + costheta = this.kxVector[wavelengthIndex][angleIndex][i].over(this.kVector[wavelengthIndex][angleIndex][i]); + pTerm = (this.refractiveIndices[wavelengthIndex][i].over(this.impedance)).over(Complex.sqrt(this.relativeMagneticPermeabilities[wavelengthIndex][i])); + pTerm = pTerm.times(costheta); + beta = this.kxVector[wavelengthIndex][angleIndex][i].times(this.thicknesses[i]); + matic[0][0] = Complex.cos(beta); + matic[1][1] = matic[0][0]; + tempc1 = Complex.sin(beta); + tempc1 = tempc1.times(Complex.minusJay()); + matic[0][1] = tempc1.over(pTerm); + matic[1][0] = tempc1.times(pTerm); + mati.setTwoDarray(Complex.copy(matic)); + mat = mat.times(mati); + matic = mat.getArrayCopy(); + } + } + + costheta = this.kxVector[wavelengthIndex][angleIndex][0].over(this.kVector[wavelengthIndex][angleIndex][0]); + Complex pTerm0 = (this.refractiveIndices[wavelengthIndex][0].over(this.impedance)).over(Complex.sqrt(this.relativeMagneticPermeabilities[wavelengthIndex][0])); + pTerm0 = pTerm0.times(costheta); + + costheta = this.kxVector[wavelengthIndex][angleIndex][this.numberOfLayers-1].over(this.kVector[wavelengthIndex][angleIndex][this.numberOfLayers-1]); + Complex pTermN = (this.refractiveIndices[wavelengthIndex][this.numberOfLayers-1].over(this.impedance)).over(Complex.sqrt(this.relativeMagneticPermeabilities[wavelengthIndex][this.numberOfLayers-1])); + pTermN = pTermN.times(costheta); + + tempc1 = matic[0][0].plus(matic[0][1].times(pTermN)); + tempc1 = tempc1.times(pTerm0); + tempc2 = matic[1][0].plus(matic[1][1].times(pTermN)); + tempc3 = tempc1.minus(tempc2); + tempc4 = tempc1.plus(tempc2); + this.reflectCoeffTE[wavelengthIndex][angleIndex] = tempc3.over(tempc4); + this.reflectPhaseShiftRadTE[wavelengthIndex][angleIndex] = this.reflectCoeffTE[wavelengthIndex][angleIndex].arg(); + this.reflectPhaseShiftDegTE[wavelengthIndex][angleIndex] = Math.toDegrees(this.reflectPhaseShiftRadTE[wavelengthIndex][angleIndex]); + + tempc3 = pTerm0.times(2.0D); + this.transmitCoeffTE[wavelengthIndex][angleIndex] = tempc3.over(tempc4); + this.transmitPhaseShiftRadTE[wavelengthIndex][angleIndex] = this.transmitCoeffTE[wavelengthIndex][angleIndex].arg(); + this.transmitPhaseShiftDegTE[wavelengthIndex][angleIndex] = Math.toDegrees(this.transmitPhaseShiftRadTE[wavelengthIndex][angleIndex]); + } + + // Calculate and return reflectivity, transmissivity, transmitted angle, evanescent field + double reflectivity = Fmath.square(this.reflectCoeffTE[wavelengthIndex][angleIndex].getReal()) + Fmath.square(this.reflectCoeffTE[wavelengthIndex][angleIndex].getImag()); + + int nkouter = this.numberOfLayers - 1; + double tempd1 = Fmath.square(this.transmitCoeffTE[wavelengthIndex][angleIndex].getReal()) + Fmath.square(this.transmitCoeffTE[wavelengthIndex][angleIndex].getImag()); + tempc2 = (this.relativeMagneticPermeabilities[wavelengthIndex][0].over(this.relativeMagneticPermeabilities[wavelengthIndex][nkouter])).times(tempd1); + tempc3 = this.kxVector[wavelengthIndex][angleIndex][nkouter].conjugate().over(this.kxVector[wavelengthIndex][angleIndex][0]); + Complex complexTransmissivity = tempc2.times(tempc3); + + double transmissivity = 0.0D; + double reflectedAngleRad = Math.PI/2.0D; + double integratedEvanescentField = 0.0D; + if(this.kxVector[wavelengthIndex][angleIndex][nkouter].getReal()==0.0D){ + penetrationDepth = 1.0D/this.kxVector[wavelengthIndex][angleIndex][nkouter].getImag(); + integratedEvanescentField = Fmath.square(this.transmitCoeffTE[wavelengthIndex][angleIndex].abs())*(1.0D - Math.exp(-2.0D*this.fieldDistance/penetrationDepth))*penetrationDepth/2.0D; + if(this.fieldDistance!=Double.POSITIVE_INFINITY)this.fieldIntensityCalc = true; + } + else{ + transmissivity = complexTransmissivity.getReal(); + reflectedAngleRad = Math.atan2(this.kzVector[wavelengthIndex][angleIndex][nkouter].getReal(), this.kxVector[wavelengthIndex][angleIndex][nkouter].getReal()); + } + + double powerLoss = 10.0D*Fmath.log10((1.0D - transmissivity)*1e-3); + + double[] ret = new double[6]; + ret[0] = reflectivity; + ret[1] = transmissivity; + ret[2] = reflectedAngleRad; + ret[3] = integratedEvanescentField; + ret[4] = penetrationDepth; + ret[5] = powerLoss; + return ret; + } + + // Calculate the reflectivities for the TM mode + public double[] calcTMreflectivity(int wavelengthIndex, int angleIndex){ + + Complex tempc1 = Complex.zero(); // temporary variable for calculations + Complex tempc2 = Complex.zero(); // temporary variable for calculations + Complex tempc3 = Complex.zero(); // temporary variable for calculations + Complex tempc4 = Complex.zero(); // temporary variable for calculations + + double penetrationDepth = 0.0D; + + if(this.numberOfLayers==2){ + tempc1 = Complex.square(this.refractiveIndices[wavelengthIndex][1]).times(this.kxVector[wavelengthIndex][angleIndex][0]); + tempc2 = Complex.square(this.refractiveIndices[wavelengthIndex][0]).times(this.kxVector[wavelengthIndex][angleIndex][1]); + tempc3 = tempc1.minus(tempc2); + tempc4 = tempc1.plus(tempc2); + this.reflectCoeffTM[wavelengthIndex][angleIndex] = tempc3.over(tempc4); + + tempc3 = tempc1.times(2.0D); + this.transmitCoeffTM[wavelengthIndex][angleIndex] = tempc3.over(tempc4); + } + else{ + // Create instance of Matrix Mi + ComplexMatrix mati = new ComplexMatrix(2, 2); + + // Create instance of Complex array Mi + Complex[][] matic = Complex.twoDarray(2, 2); + + // Calculate cos(theta[1]), beta[1], cos[beta[1]], sin[beta[1]], p[1] + Complex costheta = this.kxVector[wavelengthIndex][angleIndex][1].over(this.kVector[wavelengthIndex][angleIndex][1]); + Complex pTerm = (this.refractiveIndices[wavelengthIndex][1].over(this.impedance)).over(Complex.sqrt(this.relativeMagneticPermeabilities[wavelengthIndex][1])); + pTerm = pTerm.over(costheta); + Complex beta = this.kxVector[wavelengthIndex][angleIndex][1].times(this.thicknesses[1]); + matic[0][0] = Complex.cos(beta); + matic[1][1] = matic[0][0]; + tempc1 = Complex.sin(beta); + tempc1 = tempc1.times(Complex.minusJay()); + matic[0][1] = tempc1.over(pTerm); + matic[1][0] = tempc1.times(pTerm); + + if(this.numberOfLayers>3){ + // Create instance of Matrix M + ComplexMatrix mat = new ComplexMatrix(Complex.copy(matic)); + + for(int i=2; i<this.numberOfLayers-1;i++){ + costheta = this.kxVector[wavelengthIndex][angleIndex][i].over(this.kVector[wavelengthIndex][angleIndex][i]); + pTerm = (this.refractiveIndices[wavelengthIndex][i].over(this.impedance)).over(Complex.sqrt(this.relativeMagneticPermeabilities[wavelengthIndex][i])); + pTerm = pTerm.over(costheta); + beta = this.kxVector[wavelengthIndex][angleIndex][i].times(this.thicknesses[i]); + matic[0][0] = Complex.cos(beta); + matic[1][1] = matic[0][0]; + tempc1 = Complex.sin(beta); + tempc1 = tempc1.times(Complex.minusJay()); + matic[0][1] = tempc1.over(pTerm); + matic[1][0] = tempc1.times(pTerm); + mati.setTwoDarray(Complex.copy(matic)); + mat = mat.times(mati); + matic = mat.getArrayReference(); + } + } + costheta = this.kxVector[wavelengthIndex][angleIndex][0].over(this.kVector[wavelengthIndex][angleIndex][0]); + Complex pTerm0 = (this.refractiveIndices[wavelengthIndex][0].over(this.impedance)).over(Complex.sqrt(this.relativeMagneticPermeabilities[wavelengthIndex][0])); + pTerm0 = pTerm0.over(costheta); + + costheta = this.kxVector[wavelengthIndex][angleIndex][this.numberOfLayers-1].over(this.kVector[wavelengthIndex][angleIndex][this.numberOfLayers-1]); + Complex pTermN = (this.refractiveIndices[wavelengthIndex][this.numberOfLayers-1].over(this.impedance)).over(Complex.sqrt(this.relativeMagneticPermeabilities[wavelengthIndex][this.numberOfLayers-1])); + pTermN = pTermN.over(costheta); + + tempc1 = matic[0][0].plus(matic[0][1].times(pTermN)); + tempc1 = tempc1.times(pTerm0); + tempc2 = matic[1][0].plus(matic[1][1].times(pTermN)); + tempc3 = tempc1.minus(tempc2); + tempc4 = tempc1.plus(tempc2); + this.reflectCoeffTM[wavelengthIndex][angleIndex] = tempc3.over(tempc4); + this.reflectPhaseShiftRadTM[wavelengthIndex][angleIndex] = this.reflectCoeffTM[wavelengthIndex][angleIndex].arg(); + this.reflectPhaseShiftDegTM[wavelengthIndex][angleIndex] = Math.toDegrees(this.reflectPhaseShiftRadTM[wavelengthIndex][angleIndex]); + + tempc3 = pTerm0.times(2.0D); + this.transmitCoeffTM[wavelengthIndex][angleIndex] = tempc3.over(tempc4); + this.transmitPhaseShiftRadTM[wavelengthIndex][angleIndex] = this.transmitCoeffTM[wavelengthIndex][angleIndex].arg(); + this.transmitPhaseShiftDegTM[wavelengthIndex][angleIndex] = Math.toDegrees(this.transmitPhaseShiftRadTM[wavelengthIndex][angleIndex]); + } + + // Calculate and return reflectivity, transmissivity, transmitted angle, evanescent field + double reflectivity = Fmath.square(this.reflectCoeffTM[wavelengthIndex][angleIndex].getReal()) + Fmath.square(this.reflectCoeffTM[wavelengthIndex][angleIndex].getImag()); + + int nkouter = this.numberOfLayers - 1; + double tempd1 = Fmath.square(this.transmitCoeffTM[wavelengthIndex][angleIndex].getReal()) + Fmath.square(this.transmitCoeffTM[wavelengthIndex][angleIndex].getImag()); + tempc2 = Complex.square(this.refractiveIndices[wavelengthIndex][0].over(this.refractiveIndices[wavelengthIndex][nkouter])).times(tempd1); + tempc3 = this.kxVector[wavelengthIndex][angleIndex][nkouter].conjugate().over(this.kxVector[wavelengthIndex][angleIndex][0]); + Complex complexTransmissivity = tempc2.times(tempc3); + + double transmissivity = 0.0D; + double reflectedAngleRad = Math.PI/2.0D; + double integratedEvanescentField = 0.0D; + if(this.kxVector[wavelengthIndex][angleIndex][nkouter].getReal()==0.0D){ + penetrationDepth = 1.0D/this.kxVector[wavelengthIndex][angleIndex][nkouter].getImag(); + double refrTerm = this.refractiveIndices[wavelengthIndex][0].getReal()/this.refractiveIndices[wavelengthIndex][nkouter].getReal(); + double magnTerm = Math.sqrt(this.relativeMagneticPermeabilities[wavelengthIndex][nkouter].getReal()/this.relativeMagneticPermeabilities[wavelengthIndex][0].getReal()); + integratedEvanescentField = Fmath.square(this.transmitCoeffTM[wavelengthIndex][angleIndex].abs())*magnTerm*refrTerm*(1.0D - Math.exp(-2.0D*this.fieldDistance/penetrationDepth))*penetrationDepth/2.0D; + if(this.fieldDistance!=Double.POSITIVE_INFINITY)this.fieldIntensityCalc = true; + } + else{ + transmissivity = complexTransmissivity.getReal(); + reflectedAngleRad = Math.atan2(this.kzVector[wavelengthIndex][angleIndex][nkouter].getReal(), this.kxVector[wavelengthIndex][angleIndex][nkouter].getReal()); + } + + double powerLoss = 10.0D*Fmath.log10((1.0D - transmissivity)*1e-3); + + double[] ret = new double[6]; + ret[0] = reflectivity; + ret[1] = transmissivity; + ret[2] = reflectedAngleRad; + ret[3] = integratedEvanescentField; + ret[4] = penetrationDepth; + ret[5] = powerLoss; + return ret; + } + + // NON-LINEAR REGRESSION METHODS + + // ENTER INDICES OF PARAMETERS TO BE ESTIMATED BY NON-LINEAR REGRESSION + + // Enter indices of thicknesses to be estimated + public void setThicknessEstimatesIndices(int[] indices){ + this.thicknessEstimateIndices = indices; + this.thicknessEstimateNumber = indices.length; + } + + // Enter indices of real parts of the refractive indices to be estimated + public void setRealRefractIndexEstimateIndices(int[] indices){ + this.refractIndexRealEstimateIndices = indices; + this.refractIndexRealEstimateNumber = indices.length; + } + + // Enter indices of imaginary parts of the refractive indices to be estimated + public void setImagRefractIndexEstimateIndices(int[] indices){ + this.refractIndexImagEstimateIndices = indices; + this.refractIndexImagEstimateNumber = indices.length; + this.refractIndexImagEstimateSet = true; + + // Transfer absorption coefficient estimate indices to Imag[refractive index] estimate indices list + if(this.absorptionCoeffEstimateSet){ + int[] temp0 = new int[this.absorptionCoeffEstimateNumber]; + int newIndex = 0; + for(int i=0; i<this.numberOfLayers; i++){ + boolean testR = false; + for(int j=0; j<this.refractIndexImagEstimateNumber; j++){ + if(i==this.refractIndexImagEstimateIndices[j])testR=true; + } + boolean testA = false; + for(int j=0; j<this.absorptionCoeffEstimateNumber; j++){ + if(i==this.absorptionCoeffEstimateIndices[j])testA=true; + } + if(!testR && testA){ + temp0[newIndex] = i; + newIndex++; + } + } + int newRefrNumber = this.refractIndexImagEstimateNumber + newIndex; + int[] temp1 = new int[newRefrNumber]; + for(int j=0; j<this.refractIndexImagEstimateNumber; j++){ + temp1[j] = this.refractIndexImagEstimateIndices[j]; + } + for(int j=0; j<this.absorptionCoeffEstimateNumber; j++){ + temp1[this.refractIndexImagEstimateNumber + j] = this.absorptionCoeffEstimateIndices[j]; + } + this.refractIndexImagEstimateIndices = Fmath.selectionSort(temp1); + + } + } + + // Enter indices of absorption coefficients to be estimated + public void setAbsorptionCoefficientEstimateIndices(int[] indices){ + this.absorptionCoeffEstimateIndices = indices; + this.absorptionCoeffEstimateNumber = indices.length; + this.absorptionCoeffEstimateSet = true; + + // Transfer absorption coefficient estimate indices to Imag[refractive index] estimate indices list + if(this.refractIndexImagEstimateSet){ + int[] temp0 = new int[this.absorptionCoeffEstimateNumber]; + int newIndex = 0; + for(int i=0; i<this.numberOfLayers; i++){ + boolean testR = false; + for(int j=0; j<this.refractIndexImagEstimateNumber; j++){ + if(i==this.refractIndexImagEstimateIndices[j])testR=true; + } + boolean testA = false; + for(int j=0; j<this.absorptionCoeffEstimateNumber; j++){ + if(i==this.absorptionCoeffEstimateIndices[j])testA=true; + } + if(!testR && testA){ + temp0[newIndex] = i; + newIndex++; + } + } + int newRefrNumber = this.refractIndexImagEstimateNumber + newIndex; + int[] temp1 = new int[newRefrNumber]; + for(int j=0; j<this.refractIndexImagEstimateNumber; j++){ + temp1[j] = this.refractIndexImagEstimateIndices[j]; + } + for(int j=0; j<this.absorptionCoeffEstimateNumber; j++){ + temp1[this.refractIndexImagEstimateNumber + j] = this.absorptionCoeffEstimateIndices[j]; + } + this.refractIndexImagEstimateIndices = Fmath.selectionSort(temp1); + } + else{ + this.refractIndexImagEstimateIndices = this.absorptionCoeffEstimateIndices; + this.refractIndexImagEstimateNumber = this.absorptionCoeffEstimateNumber; + } + } + + // Enter indices of real parts of the relative magnetic permeabilities to be estimated + public void setRealRelativeMagneticPermeabilityEstimateIndices(int[] indices){ + this.magneticPermRealEstimateIndices = indices; + this.magneticPermRealEstimateNumber = indices.length; + } + + // Enter indices of imaginary parts of the relative magnetic permeabilities to be estimated + public void setImagRelativeMagneticPermeabilityEstimateIndices(int[] indices){ + this.magneticPermImagEstimateIndices = indices; + this.magneticPermImagEstimateNumber = indices.length; + } + + // FIT AND PLOT FIT - REFLECTIVITIES + + // Fit reflectivities against incident angles + // Errors (weights) not provided + public void fitReflectivities(double[] experimentalReflectivities){ + int n = experimentalReflectivities.length; + double[] errors = new double[n]; + for(int i=0; i<n; i++)errors[i] = 1.0D; + fitReflectivities(experimentalReflectivities, errors); + } + + // Fit reflectivities against incident angles + // Errors (weights) provided + public void fitReflectivities(double[] experimentalReflectivities, double[] errors){ + this.numberOfDataPoints = experimentalReflectivities.length; + if(this.numberOfDataPoints!=errors.length)throw new IllegalArgumentException("Number of data points, " + this.numberOfDataPoints + " is not equal to the number of errors (weights), " + errors.length + "."); + if(this.incidentAngleSet){ + if(this.numberOfDataPoints!=this.numberOfIncidentAngles)throw new IllegalArgumentException("Number of experimental reflectivities " + this.numberOfDataPoints + " does not equal the number of incident angles " + this.numberOfIncidentAngles); + double[] temp0 = experimentalReflectivities.clone(); + double[] temp1 = errors.clone(); + for(int i=0; i<this.numberOfIncidentAngles;i++){ + this.experimentalData[i] = temp0[this.incidentAngleIndices[i]]; + this.experimentalWeights[i] = temp1[this.incidentAngleIndices[i]]; + } + } + this.regressionOption = 1; + this.experimentalDataSet = true; + + this.nonLinearRegression(); + } + + // Fit and plot reflectivities against incident angles + // Errors (weights) not provided + // Graph title not provided + public void fitAndPlotReflectivities(double[] experimentalReflectivities){ + fitReflectivities(experimentalReflectivities); + String graphTitle = " "; + plotFit(graphTitle); + } + + // Fit and plot reflectivities against incident angles + // Errors (weights) not provided + // Graph title provided + public void fitAndPlotReflectivities(double[] experimentalReflectivities, String graphTitle){ + fitReflectivities(experimentalReflectivities); + plotFit(graphTitle); + } + + // Fit and plot reflectivities against incident angles + // Errors (weights) provided + // Graph title not provided + public void fitAndPlotReflectivities(double[] experimentalReflectivities, double[] errors){ + fitReflectivities(experimentalReflectivities, errors); + String graphTitle = " "; + plotFit(graphTitle); + } + + // Fit and plot reflectivities against incident angles + // Errors (weights) provided + // Graph title provided + public void fitAndPlotReflectivities(double[] experimentalReflectivities, double[] errors, String graphTitle){ + fitReflectivities(experimentalReflectivities, errors); + plotFit(graphTitle); + } + + // FIT AND PLOT FIT - TRANSMISSIVITIES + + // Fit transmissivities against incident angles + // Errors (weights) not provided + public void fitTransmissivities(double[] experimentalTransmissivities){ + int n = experimentalTransmissivities.length; + double[] errors = new double[n]; + for(int i=0; i<n; i++)errors[i] = 1.0D; + fitTransmissivities(experimentalTransmissivities, errors); + } + + // Fit transmissivities against incident angles + // Errors (weights) provided + public void fitTransmissivities(double[] experimentalTransmissivities, double[] errors){ + this.numberOfDataPoints = experimentalTransmissivities.length; + if(this.numberOfDataPoints!=errors.length)throw new IllegalArgumentException("Number of data points, " + this.numberOfDataPoints + " is not equal to the number of errors (weights), " + errors.length + "."); + if(this.incidentAngleSet){ + if(this.numberOfDataPoints!=this.numberOfIncidentAngles)throw new IllegalArgumentException("Number of experimental transmissivities " + this.numberOfDataPoints + " does not equal the number of incident angles " + this.numberOfIncidentAngles); + double[] temp0 = experimentalTransmissivities.clone(); + double[] temp1 = errors.clone(); + for(int i=0; i<this.numberOfIncidentAngles;i++){ + this.experimentalData[i] = temp0[this.incidentAngleIndices[i]]; + this.experimentalWeights[i] = temp1[this.incidentAngleIndices[i]]; + } + } + this.regressionOption = 1; + this.experimentalDataSet = true; + + this.nonLinearRegression(); + } + + // Fit and plot transmissivities against incident angles + // Errors (weights) not provided + // Graph title not provided + public void fitAndPlotTransmissivities(double[] experimentalTransmissivities){ + fitTransmissivities(experimentalTransmissivities); + String graphTitle = " "; + plotFit(graphTitle); + } + + // Fit and plot transmissivities against incident angles + // Errors (weights) not provided + // Graph title provided + public void fitAndPlotTransmissivities(double[] experimentalTransmissivities, String graphTitle){ + fitTransmissivities(experimentalTransmissivities); + plotFit(graphTitle); + } + + // Fit and plot transmissivities against incident angles + // Errors (weights) provided + // Graph title not provided + public void fitAndPlotTransmissivities(double[] experimentalTransmissivities, double[] errors){ + fitTransmissivities(experimentalTransmissivities, errors); + String graphTitle = " "; + plotFit(graphTitle); + } + + // Fit and plot transmissivities against incident angles + // Errors (weights) provided + // Graph title provided + public void fitAndPlotTransmissivities(double[] experimentalTransmissivities, double[] errors, String graphTitle){ + fitTransmissivities(experimentalTransmissivities, errors); + plotFit(graphTitle); + } + + // FIT AND PLOT FIT - EVANESCENT FIELDS + + // Fit total evanescent field against incident angles + // Errors (weights) not provided + // Distance into field not provided + public void fitEvanescentField(double[] experimentalEvanescentFieldIntensities){ + int n = experimentalEvanescentFieldIntensities.length; + double[] errors = new double[n]; + for(int i=0; i<n; i++)errors[i] = 1.0D; + double fieldDistance = Double.POSITIVE_INFINITY; + fitEvanescentField(experimentalEvanescentFieldIntensities, errors, fieldDistance); + } + + // Fit total evanescent field against incident angles + // Errors (weights) provided + // Distance into field not provided + public void fitEvanescentField(double[] experimentalEvanescentFieldIntensities, double[] errors){ + double fieldDistance = Double.POSITIVE_INFINITY; + this.fitEvanescentField(experimentalEvanescentFieldIntensities, errors, fieldDistance); + } + + // Fit total evanescent field against incident angles + // Errors (weights) not provided + // Distance into field provided + public void fitEvanescentField(double[] experimentalEvanescentFieldIntensities, double fieldDistance){ + int n = experimentalEvanescentFieldIntensities.length; + double[] errors = new double[n]; + for(int i=0; i<n; i++)errors[i] = 1.0D; + fitEvanescentField(experimentalEvanescentFieldIntensities, errors, fieldDistance); + } + + // Fit evanescent field to a depth of fieldDistance against incident angles + // Errors (weights) provided + // Distance into field provided + public void fitEvanescentField(double[] experimentalEvanescentFieldIntensities, double[] errors, double fieldDistance){ + this.numberOfDataPoints = experimentalEvanescentFieldIntensities.length; + if(this.numberOfDataPoints!=errors.length)throw new IllegalArgumentException("Number of data points, " + this.numberOfDataPoints + " is not equal to the number of errors (weights), " + errors.length + "."); + + if(this.incidentAngleSet){ + if(this.numberOfDataPoints!=this.numberOfIncidentAngles)throw new IllegalArgumentException("Number of experimental transmissivities " + this.numberOfDataPoints + " does not equal the number of incident angles " + this.numberOfIncidentAngles); + double[] temp0 = experimentalEvanescentFieldIntensities.clone(); + double[] temp1 = errors.clone(); + for(int i=0; i<this.numberOfIncidentAngles;i++){ + this.experimentalData[i] = temp0[this.incidentAngleIndices[i]]; + this.experimentalWeights[i] = temp1[this.incidentAngleIndices[i]]; + } + } + this.regressionOption = 3; + this.fieldDistance = fieldDistance; + this.experimentalDataSet = true; + + this.nonLinearRegression(); + } + + // NELDER AND MEAD SIMPLEX NON-LINEAR REGRESSION + + // Fit experimental data against incident angles + public void nonLinearRegression(){ + + // Weighting option + int ii=0; + boolean test = true; + while(test){ + if(this.experimentalWeights[ii]!=1.0D){ + this.weightingOption = true; + test=false; + } + else{ + ii++; + if(ii>=this.numberOfDataPoints)test=false; + } + } + + // Create an instance of Regression + Regression regr = null; + if(this.weightingOption){ + regr = new Regression(this.incidentAngleDeg, this.experimentalData, this.experimentalWeights); + } + else{ + regr = new Regression(this.incidentAngleDeg, this.experimentalData); + } + + // Create instance of regression function + RegressFunct funct0 = new RegressFunct(); + + // Transfer values to function + funct0.numberOfLayers = this.numberOfLayers; + funct0.mode = this.mode; + funct0.eVectorAngleDeg = this.eVectorAngleDeg; + funct0.thicknesses = this.thicknesses; + funct0.refractiveIndices = this.refractiveIndices; + funct0.relativeMagneticPermeabilities = this.relativeMagneticPermeabilities; + funct0.regressionOption = this.regressionOption; + funct0.thicknessEstimateIndices = this.thicknessEstimateIndices; + funct0.refractIndexRealEstimateIndices = this.refractIndexRealEstimateIndices; + funct0.refractIndexImagEstimateIndices = this.refractIndexImagEstimateIndices; + funct0.magneticPermRealEstimateIndices = this.magneticPermRealEstimateIndices; + funct0.magneticPermImagEstimateIndices = this.magneticPermImagEstimateIndices; + + // Number of estimated parameters + this.numberOfEstimatedParameters = this.thicknessEstimateNumber; + this.numberOfEstimatedParameters += this.refractIndexRealEstimateNumber; + this.numberOfEstimatedParameters += this.refractIndexImagEstimateNumber; + this.numberOfEstimatedParameters += this.magneticPermRealEstimateNumber; + this.numberOfEstimatedParameters += this.magneticPermImagEstimateNumber; + if(this.regressionOption==3)this.numberOfEstimatedParameters++; + + this.degreesOfFreedom = this.numberOfDataPoints - this.numberOfEstimatedParameters; + if(this.degreesOfFreedom<1)throw new IllegalArgumentException("Number of parameters to be estimated, " + this.numberOfEstimatedParameters + ", is greater than or equal to the number of data points, " + this.numberOfDataPoints + "."); + + // Fill initial estimate arrays + double[] start = new double[this.numberOfEstimatedParameters]; + double[] init = new double[this.numberOfEstimatedParameters]; + double[] step = new double[this.numberOfEstimatedParameters]; + + int pIndex = 0; + for(int i=0; i<this.thicknessEstimateNumber; i++){ + init[pIndex] = this.thicknesses[this.thicknessEstimateIndices[pIndex]]; + start[pIndex] = init[pIndex]; + step[pIndex] = init[pIndex]*0.1D; + if(step[pIndex]==0.0D)step[pIndex]=1e-9; + pIndex++; + } + for(int i=0; i<this.refractIndexRealEstimateNumber; i++){ + init[pIndex] = this.refractiveIndices[0][this.refractIndexRealEstimateIndices[pIndex]].getReal(); + start[pIndex] = init[pIndex]; + step[pIndex] = init[pIndex]*0.1D; + if(step[pIndex]==0.0D)step[pIndex]=0.1D; + pIndex++; + } + for(int i=0; i<this.refractIndexImagEstimateNumber; i++){ + init[pIndex] = this.refractiveIndices[0][this.refractIndexImagEstimateIndices[pIndex]].getImag(); + start[pIndex] = init[pIndex]; + step[pIndex] = init[pIndex]*0.1D; + if(step[pIndex]==0.0D)step[pIndex]=0.1D; + pIndex++; + } + for(int i=0; i<this.magneticPermRealEstimateNumber; i++){ + init[pIndex] = this.relativeMagneticPermeabilities[0][this.magneticPermRealEstimateIndices[pIndex]].getReal(); + start[pIndex] = init[pIndex]; + step[pIndex] = init[pIndex]*0.1D; + if(step[pIndex]==0.0D)step[pIndex]=0.1D; + pIndex++; + } + for(int i=0; i<this.magneticPermImagEstimateNumber; i++){ + init[pIndex] = this.relativeMagneticPermeabilities[0][this.magneticPermImagEstimateIndices[pIndex]].getImag(); + start[pIndex] = init[pIndex]; + step[pIndex] = init[pIndex]*0.1D; + if(step[pIndex]==0.0D)step[pIndex]=0.1D; + pIndex++; + } + + // calculate scaling factor estimate if evanescent field fitting option chosen + if(this.regressionOption==3){ + double[] evanFields = (double[])getEvanescentFields(this.fieldDistance); + double calcFieldMean = 0.0D; + double explFieldMean = 0.0D; + for(int i=0; i<this.numberOfDataPoints; i++){ + if(evanFields[i]!=0.0D){ + calcFieldMean += evanFields[i]; + explFieldMean += this.experimentalData[i]; + } + } + if(explFieldMean==0.0D)throw new IllegalArgumentException("All entered field values are zero or sum to zero"); + if(calcFieldMean==0.0D)throw new IllegalArgumentException("All calculated field values are zero or sum to zero"); + init[pIndex] = explFieldMean/calcFieldMean; + start[pIndex] = init[pIndex]; + step[pIndex] = init[pIndex]*0.1D; + if(step[pIndex]==0.0D)step[pIndex]=0.1D; + pIndex++; + } + + // Set tolerance for exiting regression + double ftol = 1e-6; + + // Set maximum iterations in regression + int nmax = 1000; + + // Call non-linear regression method + regr.simplex(funct0, start, step, ftol, nmax); + + // Get best estimates + double[] bestEstimates = regr.getCoeff(); + + // Load best estimates into appropriate arrays + pIndex = 0; + for(int i=0; i<this.thicknessEstimateNumber; i++){ + this.thicknesses[this.thicknessEstimateIndices[pIndex]] = bestEstimates[pIndex]; + pIndex++; + } + for(int i=0; i<this.refractIndexRealEstimateNumber; i++){ + this.refractiveIndices[0][this.refractIndexRealEstimateIndices[pIndex]].setReal(bestEstimates[pIndex]); + pIndex++; + } + for(int i=0; i<this.refractIndexImagEstimateNumber; i++){ + this.refractiveIndices[0][this.refractIndexImagEstimateIndices[pIndex]].setImag(bestEstimates[pIndex]); + pIndex++; + } + for(int i=0; i<this.magneticPermRealEstimateNumber; i++){ + this.relativeMagneticPermeabilities[0][this.magneticPermRealEstimateIndices[pIndex]].setReal(bestEstimates[pIndex]); + pIndex++; + } + for(int i=0; i<this.magneticPermImagEstimateNumber; i++){ + this.relativeMagneticPermeabilities[0][this.magneticPermImagEstimateIndices[pIndex]].setImag(bestEstimates[pIndex]); + pIndex++; + } + if(this.regressionOption==3)this.fieldScalingFactor = bestEstimates[pIndex]; + + // Get calculated data at best estimate values + switch(this.regressionOption){ + case 1: // transmissivity fitting + this.calculatedData = (double[])this.getReflectivities(); + break; + case 2: // reflectivity fitting + this.calculatedData = (double[])this.getTransmissivities(); + break; + case 3: // evanescent field fitting + this.calculatedData = (double[])this.getEvanescentFields(); + for(int i=0; i<this.numberOfDataPoints; i++)this.calculatedData[i] *= this.fieldScalingFactor; + break; + default: throw new IllegalArgumentException("Regresion option " + regressionOption + " does not exist"); + } + } + + // Return calculated data + public double[] getCalculatedData(){ + return this.calculatedData; + } + + // PLOT THE RESULTS OF THE NON-LINEAR REGRESSION + + // Plot experimetal and calculated data + public void plotFit(String graphTitle2){ + + // Create data arrays to be plotted + int numberOfCalculatedDataPoints = 200; + double[][] data = PlotGraph.data(numberOfCalculatedDataPoints, 2); + + // experimental data + for(int i=0; i<this.numberOfDataPoints; i++){ + data[0][i] = this.incidentAngleDeg[i]; + data[1][i] = this.experimentalData[i]; + } + + // calculated data + double angleIncrement = (this.incidentAngleDeg[this.numberOfIncidentAngles-1] - this.incidentAngleDeg[0])/(numberOfCalculatedDataPoints - 1); + data[2][0] = this.incidentAngleDeg[0]; + for(int i=1; i<numberOfCalculatedDataPoints-1; i++)data[2][i] = data[2][i-1] + angleIncrement; + data[2][numberOfCalculatedDataPoints-1] = this.incidentAngleDeg[this.numberOfIncidentAngles-1]; + + // Create an instance of Reflectivity + Reflectivity refl2 = new Reflectivity(this.numberOfLayers); + + // Set mode + if(this.mode.equals("mixed")){ + refl2.setMode(eVectorAngleDeg); + } + else{ + refl2.setMode(this.mode); + } + // Set thicknesses to fixed values + refl2.setThicknesses(this.thicknesses); + // Set refractive index + refl2.setRefractiveIndices(this.refractiveIndices); + // Set relative magnetic permeability + refl2.setRelativeMagneticPermeabilities(this.relativeMagneticPermeabilities); + // Set incident angles + refl2.setIncidentAngle(data[2]); + + // Calculate values and plot legends + String titleEnd = null; + String yAxis = null; + switch(regressionOption){ + case 1: // transmissivity fitting + data[3] = (double[])refl2.getReflectivities(); + titleEnd = "Plot of reflectivities versus incident angle"; + yAxis = "Reflectivity"; + break; + case 2: // reflectivity fitting + data[3] = (double[])refl2.getTransmissivities(); + titleEnd = "Plot of transmissivities versus incident angle"; + yAxis = "Transmissivity"; + break; + case 3: // evanescent field fitting + data[3] = (double[])refl2.getEvanescentFields(); + for(int i=0; i<numberOfCalculatedDataPoints; i++)data[3][i] *= this.fieldScalingFactor; + titleEnd = "Plot of evanescent fields versus incident angle"; + yAxis = "Evanescent Field"; + break; + default: throw new IllegalArgumentException("Regresion option " + regressionOption + " does not exist"); + } + + // Create instance of PlotGraph + PlotGraph pg = new PlotGraph(data); + + pg.setGraphTitle("Reflectivity class: " + titleEnd); + pg.setGraphTitle2(graphTitle2); + pg.setXaxisLegend("Incident angle"); + pg.setXaxisUnitsName("degrees"); + pg.setYaxisLegend(yAxis); + + int[] pointsOptions = {1, 0}; + pg.setPoint(pointsOptions); + + int[] lineOptions = {0, 3}; + pg.setLine(lineOptions); + + pg.plot(); + } + + } + +// REGRESSION FUNCTION CLASS + +// Class providing function for fitting reflectivities, transmissivities or evanescent fields over a range of angles +class RegressFunct implements RegressionFunction{ + + public int numberOfLayers = 0; // number of layers + public String mode = null; // polarisation mode: TE, TM, unpolarised or mixed + public double eVectorAngleDeg = 0.0D; // the electric vector angle + public double[] thicknesses = null; // the electric vector angle + public double[] incidentAnglesDeg = null; // the incident angles + public Complex[][] refractiveIndices = null; // refractive indices + public Complex[][] relativeMagneticPermeabilities = null; // relative magnetic permeabilities + public int regressionOption = 0; // Regression option + // = 1; reflectivity versus angle + // = 2; transmissivity versus angle + // = 3; evanescent field versus angle + public int[] thicknessEstimateIndices = null; // indices of the thicknesses to be estimated by non-linear regression + public int[] refractIndexRealEstimateIndices = null; // indices of the Real[refractive indices] to be estimated by non-linear regression + public int[] refractIndexImagEstimateIndices = null; // indices of the Imag[refractive indices] to be estimated by non-linear regression + public int[] magneticPermRealEstimateIndices = null; // indices of the Real[relative magnetic permeability] to be estimated by non-linear regression + public int[] magneticPermImagEstimateIndices = null; // indices of the Imag[relative magnetic permeability] to be estimated by non-linear regression + + public double function(double[ ] p, double[ ] x){ + + // Create instance oF Reflectivity for single angle calculation + Reflectivity refl = new Reflectivity(this.numberOfLayers); + + // set polarisation mode + if(this.mode.equals("mixed")){ + refl.setMode(eVectorAngleDeg); + } + else{ + refl.setMode(this.mode); + } + + // Add estimates of thicknesses to fixed values + int pIndex =0; + int n = this.thicknessEstimateIndices.length; + for(int i=0; i<n; i++){ + this.thicknesses[thicknessEstimateIndices[i]] = p[pIndex]; + pIndex++; + } + // Set thicknesses to fixed values + refl.setThicknesses(this.thicknesses); + + // Add estimates of Real[refractive index] to fixed values + n = this.refractIndexRealEstimateIndices.length; + for(int i=0; i<n; i++){ + this.refractiveIndices[0][this.refractIndexRealEstimateIndices[i]].setReal(p[pIndex]); + pIndex++; + } + + // Add estimates of Imag[refractive index] to fixed values + n = this.refractIndexImagEstimateIndices.length; + for(int i=0; i<n; i++){ + this.refractiveIndices[0][this.refractIndexImagEstimateIndices[i]].setImag(p[pIndex]); + pIndex++; + } + + // Set refractive index + refl.setRefractiveIndices(this.refractiveIndices); + + // Add estimates of Real[relative magnetic permeability] to fixed values + n = this.magneticPermRealEstimateIndices.length; + for(int i=0; i<n; i++){ + this.relativeMagneticPermeabilities[0][this.magneticPermRealEstimateIndices[i]].setReal(p[pIndex]); + pIndex++; + } + + // Add estimates of Imag[relative magnetic permeability] to fixed values + n = this.magneticPermImagEstimateIndices.length; + for(int i=0; i<n; i++){ + this.relativeMagneticPermeabilities[0][this.magneticPermImagEstimateIndices[i]].setImag(p[pIndex]); + pIndex++; + } + + // Set relative magnetic permeability + refl.setRelativeMagneticPermeabilities(this.relativeMagneticPermeabilities); + + // Set incident angle for this function calculation + refl.setIncidentAngle(x[0]); + + // Calculate value returned by this function + double returnValue = 0.0; + switch(regressionOption){ + case 1: // transmissivity fitting + returnValue = ((double[])refl.getReflectivities())[0]; + break; + case 2: // reflectivity fitting + returnValue = ((double[])refl.getTransmissivities())[0]; + break; + case 3: // evanescent field fitting + returnValue = p[pIndex]*((double[])refl.getEvanescentFields())[0]; + break; + default: throw new IllegalArgumentException("Regresion option " + regressionOption + " does not exist"); + } + + return returnValue; + + } +} diff --git a/src/main/java/flanagan/optics/RefractiveIndex.java b/src/main/java/flanagan/optics/RefractiveIndex.java new file mode 100755 index 0000000000000000000000000000000000000000..256ae32c278e73e834d9058dcd14a4dd8b49d1cb --- /dev/null +++ b/src/main/java/flanagan/optics/RefractiveIndex.java @@ -0,0 +1,605 @@ +/* +* RefractiveIndex Class +* +* Methods for returning the refractive index, for a given wavelength, +* of gold, silver, fused quartz, crown glass, float glass, +* microscope slide glass, polymethacrylate, air, +* water, sodium chloride solutions, sucrose solutions, PVA solutions. +* Methods for calculating refractive index of mixtures and interconverting +* absorption coefficients and imaginary refractive indices. +* +* Methods for returning the physical properties of water: +* viscosity, density, refractive index, +* electrical permittivity, molecular weight. +* +* Author: Dr Michael Thomas Flanagan. +* +* Created: 28 February 2006 REPLACING RefrIndex (which was created July 2003 and updated 1 July 2003, 1 May 2004) +* Revision: 6 March 2006, 17 November 2006, 7 October 2007 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/RefractiveIndex.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) February 2006 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.optics; + +import flanagan.interpolation.CubicSpline; +import flanagan.interpolation.BiCubicSpline; +import flanagan.complex.Complex; +import flanagan.physprop.*; + +public class RefractiveIndex{ + + private static double imagPlusMinus = -1.0D; // = -1; complex refractive index = n - jk [default option] + // = +1; complex refractive index = n + jk + + // METHODS + + // Resets complex refractive index as n + jk + public static void setComlexImagAsPositive(){ + RefractiveIndex.imagPlusMinus = 1.0D; + } + + // Resets complex refractive index as n - jk (default option) + public static void setComlexImagAsNegative(){ + RefractiveIndex.imagPlusMinus = -1.0D; + } + + // Returns a complex refractive index given the real part of the refractive index (riReal), + // the extinction coefficient (extCoeff)and the concentration of the absorbing species (concn) + // and the wavelength (wavl). For a pure material with a given absorption coefficient set concn + // to unity and extCoeff to the value of the absorption coefficient. + // The units of the concentration, the absorption coefficient and the wavelength should match. + public static Complex absToComplex(double riReal, double extCoeff, double concn, double wavl){ + Complex ri = new Complex(); + ri.reset(riReal, extCoeff*concn*wavl/(4.0D*Math.PI)); + return ri; + } + + // Returns the absorption coefficient ( units - reciprocal metres) that corresponds + // to the imaginary part of a complex refractive index (riImag) at a wavelength wavl (metres) + public static double imagToAbs(double riImag, double wavl){ + return 4.0D*riImag*Math.PI/wavl; + } + + // Returns the complex refractive index of GOLD for a given wavelength (in metres) + // Interpolation - natural cubic spline + // Data - P.B. Johnson and R.W. Christy, Phys. Rev. B. 6(12) 4370-4379, 1972 + public static Complex gold(double wavelength){ + // wavelengths + double[] wavl = {1.87855e-007, 1.91629e-007, 1.9525e-007, 1.99331e-007, 2.03253e-007, 2.07331e-007, 2.11939e-007, 2.16377e-007, 2.214e-007, 2.26248e-007, 2.31314e-007, 2.37063e-007, 2.4263e-007, 2.48964e-007, 2.55111e-007, 2.6157e-007, 2.68946e-007, 2.76134e-007, 2.84367e-007, 2.92415e-007, 3.00932e-007, 3.10737e-007, 3.20372e-007, 3.31508e-007, 3.42497e-007, 3.5424e-007, 3.67905e-007, 3.81489e-007, 3.97385e-007, 4.1328e-007, 4.305e-007, 4.50851e-007, 4.71422e-007, 4.95936e-007, 5.20941e-007, 5.48602e-007, 5.82085e-007, 6.16836e-007, 6.5949e-007, 7.04455e-007, 7.56e-007, 8.21086e-007, 8.91972e-007, 9.84e-007, 1.08758e-006, 1.21553e-006, 1.39308e-006, 1.61018e-006, 1.93725e-006}; + // refractive index - real part + double[] rfInRe = {1.28, 1.32, 1.34, 1.33, 1.33, 1.3, 1.3, 1.3, 1.3, 1.31, 1.3, 1.32, 1.32, 1.33, 1.33, 1.35, 1.38, 1.43, 1.47, 1.49, 1.53, 1.53, 1.54, 1.48, 1.48, 1.5, 1.48, 1.46, 1.47, 1.46, 1.45, 1.38, 1.31, 1.04, 0.62, 0.43, 0.29, 0.21, 0.14, 0.13, 0.14, 0.16, 0.17, 0.22, 0.27, 0.35, 0.43, 0.56, 0.92}; + // refractive index - imaginary part + double[] rfInIm = {1.188, 1.203, 1.226, 1.251, 1.277, 1.304, 1.35, 1.387, 1.427, 1.46, 1.497, 1.536, 1.577, 1.631, 1.688, 1.749, 1.803, 1.847, 1.869, 1.878, 1.889, 1.893, 1.898, 1.883, 1.871, 1.866, 1.895, 1.933, 1.952, 1.958, 1.948, 1.914, 1.849, 1.833, 2.081, 2.455, 2.863, 3.272, 3.697, 4.103, 4.542, 5.083, 5.663, 6.35, 7.15, 8.145, 9.519, 11.21, 13.78}; + // second derivatives - real part + double[] derivRe = {0, -1.17631e+015, -3.60547e+015, 2.92961e+015, -4.45568e+015, 3.84052e+015, -9.56586e+014, -8.80015e+013, 1.17669e+015, -2.14766e+015, 2.49889e+015, -1.81842e+015, 1.06253e+015, -8.99034e+014, 1.01496e+015, -2.29767e+014, 7.62849e+014, -4.44179e+014, -5.30697e+014, 8.3214e+014, -1.17757e+015, 8.04127e+014, -1.40022e+015, 1.06549e+015, 7.02889e+013, -3.99e+014, 3.29142e+013, 2.65475e+014, -2.19619e+014, 1.38062e+014, -3.11414e+014, 1.90132e+014, -4.37649e+014, -4.12661e+014, 6.75965e+014, -4.75615e+013, 9.68919e+013, -1.02252e+013, 5.115e+013, -3.33214e+011, 5.09764e+012, -7.56272e+012, 1.02639e+013, -4.28914e+012, 3.57066e+012, -2.76676e+012, 1.04546e+012, 2.55831e+012, 0}; + // second derivatives - imaginary part + double[] derivIm = {0, 1.07557e+015, -4.54022e+014, 4.27299e+014, -5.01416e+014, 1.54402e+015, -9.99891e+014, 2.48281e+014, -4.98264e+014, 3.40549e+014, -2.67834e+014, 1.65108e+014, 2.31595e+014, 8.3984e+013, 1.49838e+014, -5.0561e+014, 3.84443e+013, -6.38396e+014, -1.55687e+014, 1.24515e+014, -2.15188e+014, 1.55368e+014, -3.38857e+014, 1.24305e+014, -1.79372e+013, 2.93519e+014, 4.26729e+013, -1.68238e+014, -1.7188e+013, -7.16957e+013, -4.22518e+013, -1.04677e+014, 2.39351e+013, 6.13432e+014, 8.33595e+013, -9.04645e+013, 2.22081e+013, -7.1846e+013, -1.13135e+013, -1.24725e+013, -3.07173e+012, 2.01135e+012, -1.58933e+013, 7.97278e+012, -1.02502e+012, -2.60397e+011, 3.57043e+011, 3.07012e+011, 0}; + int n = wavl.length; + double yRe, yIm; + Complex ri = new Complex(); + + if(wavelength>=wavl[0] && wavelength<=wavl[n-1]){ + // cubic spline interpolation - real part + yRe=CubicSpline.interpolate(wavelength, wavl, rfInRe, derivRe); + // cubic spline interpolation - imaginary part + yIm=CubicSpline.interpolate(wavelength, wavl, rfInIm, derivIm); + ri.reset(yRe, RefractiveIndex.imagPlusMinus*yIm); + } + else{ + throw new IllegalArgumentException("Wavelength is outside the limits (187.86nm - 1937.2nm) of the tabulated data"); + } + return ri; + } + + // Returns the complex refractive index of SILVER for a given wavelength (in metres) + // Interpolation - natural cubic spline + // Data - P.B. Johnson and R.W. Christy, Phys. Rev. B. 6(12) 4370-4379, 1972 + public static Complex silver(double wavelength){ + // wavelengths + double[] wavl = {1.87855e-007, 1.91629e-007, 1.9525e-007, 1.99331e-007, 2.03253e-007, 2.07331e-007, 2.11939e-007, 2.16377e-007, 2.214e-007, 2.26248e-007, 2.31314e-007, 2.37063e-007, 2.4263e-007, 2.48964e-007, 2.55111e-007, 2.6157e-007, 2.68946e-007, 2.76134e-007, 2.84367e-007, 2.92415e-007, 3.00932e-007, 3.10737e-007, 3.20372e-007, 3.31508e-007, 3.42497e-007, 3.5424e-007, 3.67905e-007, 3.81489e-007, 3.97385e-007, 4.1328e-007, 4.305e-007, 4.50851e-007, 4.71422e-007, 4.95936e-007, 5.20941e-007, 5.48602e-007, 5.82085e-007, 6.16836e-007, 6.5949e-007, 7.04455e-007, 7.56e-007, 8.21086e-007, 8.91972e-007, 9.84e-007, 1.08758e-006, 1.21553e-006, 1.39308e-006, 1.61018e-006, 1.93725e-006}; + // refractive index - real part + double[] rfInRe = {1.07, 1.1, 1.12, 1.14, 1.15, 1.18, 1.2, 1.22, 1.25, 1.26, 1.28, 1.28, 1.3, 1.31, 1.33, 1.35, 1.38, 1.41, 1.41, 1.39, 1.34, 1.13, 0.81, 0.17, 0.14, 0.1, 0.07, 0.05, 0.05, 0.05, 0.04, 0.04, 0.05, 0.05, 0.05, 0.06, 0.05, 0.06, 0.05, 0.04, 0.03, 0.04, 0.04, 0.04, 0.04, 0.09, 0.13, 0.15, 0.24}; + // refractive index - imaginary part + double[] rfInIm = {1.212, 1.232, 1.255, 1.277, 1.296, 1.312, 1.325, 1.336, 1.342, 1.344, 1.357, 1.367, 1.378, 1.389, 1.393, 1.387, 1.372, 1.331, 1.264, 1.161, 0.964, 0.616, 0.392, 0.829, 1.142, 1.419, 1.657, 1.864, 2.07, 2.275, 2.462, 2.657, 2.869, 3.093, 3.324, 3.586, 3.858, 4.152, 4.483, 4.838, 5.242, 5.727, 6.312, 6.992, 7.795, 8.828, 10.1, 11.85, 14.08}; + // second derivatives - real part + double[] derivRe = {0, -1.09443e+015, 4.50671e+014, -1.64535e+015, 2.64916e+015, -1.73921e+015, 2.84877e+014, 8.69272e+014, -1.77518e+015, 1.48932e+015, -1.89758e+015, 1.70681e+015, -1.10717e+015, 7.52799e+014, -2.81357e+014, 2.35816e+014, 1.51436e+014, -7.66855e+014, -3.01095e+014, 1.50003e+014, -2.68399e+015, 3.86776e+014, -6.17426e+015, 9.62736e+015, -2.62139e+015, 7.94178e+014, -1.68944e+014, 1.98255e+014, -3.52453e+013, -5.72818e+013, 5.05039e+013, 3.32047e+013, -4.0284e+013, 1.33103e+012, 3.42212e+013, -5.30981e+013, 4.73552e+013, -3.35549e+013, 9.74718e+012, -4.54863e+012, 1.1835e+013, -6.76495e+012, 2.08137e+012, -2.15834e+012, 6.30268e+012, -2.73772e+012, -7.13134e+011, 1.15139e+012, 0}; + // second derivatives - imaginary part + double[] derivIm = {0, 5.49257e+014, -4.99584e+014, -1.45243e+013, -2.5674e+014, -3.33755e+014, 5.01553e+013, -3.21087e+014, -3.68608e+014, 8.65942e+014, -4.85862e+014, 2.02151e+014, -6.51859e+013, -1.59369e+014, -3.45625e+014, 3.33754e+013, -7.21153e+014, -1.75627e+014, -4.86315e+014, -1.32704e+015, -1.65707e+015, -2.19007e+014, 1.01945e+016, -4.17064e+015, 5.88854e+014, -8.77761e+014, 4.82107e+013, -2.72544e+014, 1.09375e+014, -1.88393e+014, -8.63708e+013, 1.01638e+014, -1.07779e+014, 2.5244e+013, 2.97971e+013, -8.56009e+013, 4.64112e+013, -4.16531e+013, 1.48883e+013, -5.07977e+011, -1.77458e+013, 2.84057e+013, -2.4881e+013, 9.90519e+012, 5.74546e+012, -1.37589e+013, 1.24799e+013, -9.3404e+012, 0}; + int n = wavl.length; + double yRe, yIm; + Complex ri = new Complex(); + + if(wavelength>=wavl[0] && wavelength<=wavl[n-1]){ + // cubic spline interpolation - real part + yRe=CubicSpline.interpolate(wavelength, wavl, rfInRe, derivRe); + // cubic spline interpolation - imaginary part + yIm=CubicSpline.interpolate(wavelength, wavl, rfInIm, derivIm); + ri.reset(yRe, RefractiveIndex.imagPlusMinus*yIm); + } + else{ + throw new IllegalArgumentException("Wavelength is outside the limits (187.86nm - 1937.2nm) of the tabulated data"); + } + return ri; + } + + // Returns the real refractive index of FUSED QUARTZ for a given wavelength (in metres) + // Interpolation - natural cubic spline + // Extrapolation - Cauchy equation + public static double quartz(double wavelength){ + // wavelengths + double[] wavl = {185.0e-9, 214.0e-9, 275.0e-9, 361.0e-9, 509.0e-9, 589.0e-9, 656.0e-9}; + // refractive index - real part + double[] rfInRe = {1.57464, 1.53386, 1.49634, 1.47503, 1.4619, 1.4583, 1.4564}; + // second derivatives - real part + double[] derivRe = {0.0, 2.58206e+013, 1.62375e+012, 1.75944e+012, -5.81947e+010, 3.55464e+011, 0.0}; + // Cauchy coefficients + double a1=0.444046, b1=9.677366e-15; + int n = wavl.length; + + double yRe; + + if(wavelength>=wavl[0] && wavelength<=wavl[n-1]){ + // cubic spline interpolation - real part + yRe=CubicSpline.interpolate(wavelength, wavl, rfInRe, derivRe); + } + else{ + System.out.println("Wavelength passed ("+wavelength*1e7+"nm) to RefractiveIndex.quartz() is outside"); + System.out.println("the experimental data limits (185.0 nm - 656.0 nm). Extrapolation used"); + System.out.println("the Caunchy equation which may not be valid at the wavelength requested,"); + System.out.println(" especially if the wavelength is within an absorption band"); + yRe=1.0+a1*(1.0+b1/Math.pow(wavelength,2)); + } + return yRe; + } + + // Returns the real refractive index of LAF78847 CROWN GLASS for a given wavelength (in metres) + // Interpolation - natural cubic spline + // Extrapolation - Cauchy equation + public static double crownGlass(double wavelength){ + // wavelengths + double[] wavl = {365.02e-9, 404.66e-9, 435.84e-9, 479.99e-9, 486.13e-9, 546.07e-9, 587.56e-9, 643.85e-9, 656.28e-9, 706.52e-9, 852.11e-9, 1014e-9}; + // refractive index - real part + double[] rfInRe = {1.83028, 1.8169, 1.80916, 1.8009, 1.79994, 1.79227, 1.78831, 1.7841, 1.7833, 1.78048, 1.7746, 1.77018}; + // second derivatives - real part + double[] derivRe = {0, 3.48108e+012, 1.37108e+012, 1.17265e+012, 9.68655e+011, 5.86009e+011, 4.3771e+011, 2.48861e+011, 3.01116e+011, 1.7006e+011, 8.74046e+010, 0}; + // Cauchy coefficients + double a1=0.762002, b1=1.18516e-14; + int n = wavl.length; + + double yRe; + + if(wavelength>=wavl[0] && wavelength<=wavl[n-1]){ + // cubic spline interpolation - real part + yRe=CubicSpline.interpolate(wavelength, wavl, rfInRe, derivRe); + } + else{ + System.out.println("Wavelength passed ("+wavelength*1e7+"nm) to RefractiveIndex.crownGlass() is outside"); + System.out.println("the experimental data limits (365.02 nm - 1014.0 nm). Extrapolation used"); + System.out.println("the Caunchy equation which may not be valid at the wavelength requested,"); + System.out.println(" especially if the wavelength is within an absorption band"); + yRe=1.0+a1*(1.0+b1/Math.pow(wavelength,2)); + } + return yRe; + } + + // Returns the real refractive index of PILKINGTON PERMABLOC FLOAT GLASS for a given wavelength (in metres) + // Interpolation - natural cubic spline + // Extrapolation - Cauchy equation + public static double floatGlass(double wavelength){ + // wavelengths + double[] wavl = {543.5e-9, 594.1e-9, 604e-9, 611.9e-9, 632.8e-9}; + // refractive index - real part + double[] rfInRe = {1.51958, 1.51707, 1.51671, 1.5163, 1.51553}; + // second derivatives - real part + double[] derivRe = {0, 9.28695e+011, -3.3258e+012, 2.02454e+012, 0}; + // Cauchy coefficients + double a1=0.504167, b1=9.03525e-15; + int n = wavl.length; + + double yRe; + + if(wavelength>=wavl[0] && wavelength<=wavl[n-1]){ + // cubic spline interpolation - real part + yRe=CubicSpline.interpolate(wavelength, wavl, rfInRe, derivRe); + } + else{ + System.out.println("Wavelength passed ("+wavelength*1e7+"nm) to RefractiveIndex.floatGlass() is outside"); + System.out.println("the experimental data limits (543.5 nm - 632.8 nm). Extrapolation used"); + System.out.println("the Caunchy equation which may not be valid at the wavelength requested,"); + System.out.println(" especially if the wavelength is within an absorption band"); + yRe=1.0+a1*(1.0+b1/Math.pow(wavelength,2)); + } + return yRe; + } + + // Returns the real refractive index of CHANCE POPPER MICROSCOPE SLIDE GLASS for a given wavelength (in metres) + // Interpolation - natural cubic spline + // Extrapolation - Cauchy equation + public static double microscopeSlideGlass(double wavelength){ + // wavelengths + double[] wavl = {543.5e-9, 594.1e-9, 604e-9, 611.9e-9, 632.8e-9}; + // refractive index - real part + double[] rfInRe = {1.51436, 1.51184, 1.51144, 1.51111, 1.51027}; + // second derivatives - real part + double[] derivRe = {0, 5.00315e+011, -4.19006e+011, 2.22131e+011, 0}; + // Cauchy coefficients + double a1=0.498854, b1=9.18748e-15; + int n = wavl.length; + + double yRe; + + if(wavelength>=wavl[0] && wavelength<=wavl[n-1]){ + // cubic spline interpolation - real part + yRe=CubicSpline.interpolate(wavelength, wavl, rfInRe, derivRe); + } + else{ + System.out.println("Wavelength passed ("+wavelength*1e7+"nm) to RefractiveIndex.microSlideGlass() is outside"); + System.out.println("the experimental data limits (543.5 nm - 632.8 nm). Extrapolation used"); + System.out.println("the Caunchy equation which may not be valid at the wavelength requested,"); + System.out.println(" especially if the wavelength is within an absorption band"); + yRe=1.0+a1*(1.0+b1/Math.pow(wavelength,2)); + } + return yRe; + } + + // Returns the real refractive index of POLYMETHACRYLATE for a given wavelength (in metres) + // Interpolation - natural cubic spline + // Extrapolation - Cauchy equation + public static double polymethacrylate(double wavelength){ + // wavelengths + double[] wavl = {435.8e-9, 546.1e-9, 589.3e-9}; + // refractive index - real part + double[] rfInRe = {1.502, 1.494, 1.492}; + // second derivatives - real part + double[] derivRe = {0, 5.127e+011, 0}; + // Cauchy coefficients + double a1=0.498854, b1=9.18748e-15; + int n = wavl.length; + + double yRe; + + if(wavelength>=wavl[0] && wavelength<=wavl[n-1]){ + // cubic spline interpolation - real part + yRe=CubicSpline.interpolate(wavelength, wavl, rfInRe, derivRe); + } + else{ + System.out.println("Wavelength passed ("+wavelength*1e7+"nm) to RefrIndex.polymethacrylate() is outside"); + System.out.println("the experimental data limits (435.8 nm - 589.3 nm). Extrapolation used"); + System.out.println("the Caunchy equation which may not be valid at the wavelength requested,"); + System.out.println(" especially if the wavelength is within an absorption band"); + yRe=1.0+a1*(1.0+b1/Math.pow(wavelength,2)); + } + return yRe; + } + + // Returns the real refractive index of AIR for a given wavelength (in metres) + // Interpolation - uses the Cauchy equation (see Born & Wolf section 2.3) + // Extrapolation - uses the Cauchy equation - may be invalid and will be invalid within an absorption band + public static double air(double wavelength){ + // Cauchy coefficients + double ri, a1=28.79e-5, b1=5.67e-11; + + wavelength=wavelength*1e2; + if(wavelength<2.498e-5 || wavelength>7.594e-5){ + System.out.println("Wavelength passed ("+wavelength*1e7+"nm) to RefractiveIndex.air() is outside"); + System.out.println("the experimental data limits (249.8 nm - 759.4 nm). Extrapolation using"); + System.out.println("the Caunchy equation may not be valid at the wavelength requested,"); + System.out.println(" especially if the wavelength is within an absorption band"); + } + ri=1.0+a1*(1.0+b1/Math.pow(wavelength,2)); + return ri; + } + + // Returns the real refractive index of WATER + // for a given wavelength (in metres)and a given temperature (Celsius) + // Interpolation - natural bicubic spline + public static double water(double wavelength, double temperature){ + // wavelengths + double[] wavl = {404.6e-9, 589.32e-9, 706.52e-9}; + // temperatures + double[] temp = {0,10,20,30,40,50,60,70,80,90,100}; + // refractive indices for the three wavelengths - real part + double[] rfInRe1 = {1.34359, 1.34351, 1.34287, 1.3418, 1.34039, 1.33867, 1.33669, 1.33447, 1.33204, 1.32942, 1.32663}; + double[] rfInRe2 = {1.33346, 1.33341, 1.33283, 1.33184, 1.33052, 1.32892, 1.32707, 1.325, 1.32274, 1.32029, 1.31766}; + double[] rfInRe3 = {1.33086, 1.33073, 1.33007, 1.32903, 1.32766, 1.32603, 1.32417, 1.32209, 1.31983, 1.31739, 1.31481}; + // second derivatives - real part + double[] derivRe1 = {0, -7.46454e-006, -3.74183e-006, -3.36815e-006, -3.18559e-006, -2.4895e-006, -2.4564e-006, -2.08489e-006, -1.80403e-006, -2.09899e-006, 0}; + double[] derivRe2 = {0, -7.06563e-006, -3.53749e-006, -3.3844e-006, -2.72489e-006, -2.51602e-006, -2.21102e-006, -1.83991e-006, -1.82936e-006, -2.24266e-006, 0}; + double[] derivRe3 = {0, -7.19933e-006, -3.00268e-006, -3.58995e-006, -2.43753e-006, -2.25994e-006, -2.32269e-006, -1.64928e-006, -1.88019e-006, -1.62995e-006, 0}; + int i; + int n = wavl.length; + int m = temp.length; + double[] yt = new double[n]; + double yRe; + + if(wavelength<wavl[0] || wavelength>wavl[n-1]){ + throw new IllegalArgumentException("Wavelength " + wavelength + " is out of experimental data bounds: " + wavl[0] + " to " + wavl[n-1]); + } + if(temperature<temp[0] || temperature>temp[m-1]){ + throw new IllegalArgumentException("Temperature " + temperature + " is out of experimental data bounds; "+ temp[0] + " to " + temp[m-1]); + } + + // cubic spline interpolation with respect to temperature + yt[0]=CubicSpline.interpolate(temperature, temp, rfInRe1, derivRe1); + yt[1]=CubicSpline.interpolate(temperature, temp, rfInRe2, derivRe2); + yt[2]=CubicSpline.interpolate(temperature, temp, rfInRe3, derivRe3); + + // cubic spline interpolation with respect to wavelength + CubicSpline cs = new CubicSpline(wavl, yt); + cs.calcDeriv(); + yRe = cs.interpolate(wavelength); + + return yRe; + } + + // Returns the refractive index of pva solutions as a function of g/l pva concentration + // Data Poly(vinyl alcohol): basic properties and uses by J G Pritchard (1970) + // pva refractive index increment fitted to modified Cauchy equation: + // dn = 1 + a1*(1 + b1/(lambda*lambda)) + // concn g/l concentration of pva + // temp temperature (degree Celsius) (t = 30C for original pva increment calculation) + // wavl wavelength in metres + public static double pva(double concn, double wavl, double temp){ + double refind, rfwater, rfincr; + double a1=-0.998419, b1=-1.87778e-17; + + rfwater=water(wavl, temp); + rfincr = 1.0 + a1*(1.0 + b1/Math.pow(wavl, 2)); + refind = rfwater + rfincr*concn/10.0; + + return refind; + } + + // Returns the refractive index of a NaCl solution for a given wavelength (in metres), + // a given temperature (degrees Celcius) and a given NaCl concentration (M) + // Interpolation - bicubic spline + public static double saline(double concentration, double wavelength, double temperature){ + double[] naclConcRi={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1, 11.1, 12.1, 13.1, 14.1, 15.1, 16.2, + 17.2, 18.2, 19.2, 20.2, 21.3, 22.3, 23.3, 24.4, 25.4, 26.4, 27.5, 28.5, 29.5, 30.6, 31.6, + 32.7, 33.7, 34.8, 35.8, 36.9, 37.9, 39, 40, 41.1, 42.1, 43.2, 44.2, 45.3, 46.4, 47.4, + 48.5, 49.6, 50.6, 51.7, 53.8, 56, 58.1, 60.3, 62.5, 64.6, 66.8, 69, 71.2, 73.4, + 75.6, 77.8, 80, 82.2, 84.5, 86.7, 88.9, 91.2, 93.4, 95.7, 98, 100.2, 102.5, 104.8, + 107.1, 112.8, 118.6, 124.4, 130.3, 136.2, 142.1, 148.1, 154.1, 160.2, 166.3, + 178.6, 191.1, 203.7, 216.6, 229.6, 247.2, 256.1, 269.6, 283.3, 297.2, 311.3}; + double[] rfIn={1.333, 1.3332, 1.3333, 1.3335, 1.3337, 1.3339, 1.334, 1.3342, 1.3344, 1.3346, + 1.3347, 1.3349, 1.3351, 1.3353, 1.3354, 1.3356, 1.3358, 1.336, 1.3362, 1.3363, + 1.3365, 1.3367, 1.3369, 1.337, 1.3372, 1.3374, 1.3376, 1.3377, 1.3379, 1.3381, + 1.3383, 1.3384, 1.3386, 1.3388, 1.339, 1.3391, 1.3393, 1.3395, 1.3397, 1.3398, + 1.34, 1.3402, 1.3404, 1.3405, 1.3407, 1.3409, 1.3411, 1.3412, 1.3414, 1.3416, + 1.3418, 1.3421, 1.3425, 1.3428, 1.3432, 1.3435, 1.3439, 1.3442, 1.3446, 1.3449, + 1.3453, 1.3456, 1.346, 1.3463, 1.3467, 1.347, 1.3474, 1.3477, 1.3481, 1.3484, + 1.3488, 1.3491, 1.3495, 1.3498, 1.3502, 1.3505, 1.3514, 1.3523, 1.3532, 1.3541, + 1.3549, 1.3558, 1.3567, 1.3576, 1.3585, 1.3594, 1.3612, 1.363, 1.3648, 1.3666, + 1.3684, 1.3702, 1.3721, 1.3739, 1.3757, 1.3776, 1.3795}; + double[] deriv = {0, -0.000204904, 0.000219616, -7.35613e-005, 7.4629e-005, -0.000224955, 0.00022519, -7.58054e-005, 7.80315e-005, -0.000236321, 0.000236336, -7.81129e-005, 7.61157e-005, -0.00022635, 0.000229284, -9.07847e-005, 3.90193e-005, 4.50731e-005, -0.000219312, 0.000232174, -0.000109384, 0.000107407, -0.000221696, 0.000179377, -3.70715e-005, 6.74765e-005, -0.000232834, 0.000232621, -6.63432e-005, 3.27522e-005, -0.000163915, 0.000161508, -2.13737e-005, 2.12013e-005, -0.000160693, 0.000160681, -2.11441e-005, 2.11468e-005, -0.000160694, 0.000160744, -2.1382e-005, 2.20772e-005, -0.00016403, 0.000173733, -6.79449e-005, 9.80467e-005, -0.000227966, 0.00018624, -2.11277e-005, -7.03714e-006, -5.30975e-005, 5.41898e-005, -5.48913e-005, 5.67056e-005, -6.30137e-005, 7.13824e-005, -7.17063e-005, 6.45891e-005, -6.26832e-005, 6.21769e-005, -6.20574e-005, 6.20859e-005, -6.23194e-005, 6.32246e-005, -6.66119e-005, 6.61361e-005, -6.07803e-005, 5.30183e-005, -5.13701e-005, 5.23148e-005, -5.76185e-005, 6.47375e-005, -6.44613e-005, 5.62732e-005, -4.721e-005, 1.91454e-005, -5.78664e-006, 1.31552e-006, 5.24579e-007, -6.04837e-006, 6.43247e-006, -2.44509e-006, 8.31233e-007, -8.79838e-007, 2.54193e-007, -1.36934e-007, -3.01506e-007, 2.07215e-007, -1.07068e-006, 2.48527e-006, -9.3358e-006, 1.82903e-005, -1.54847e-005, 3.70622e-006, -3.10434e-007, -1.30682e-007, 0}; + double[] wavlRockSalt = {185.0e-9, 589.0e-9, 884.0e-9, 1179.0e-9, 2357.0e-9, 3536.0e-9, 5893.0e-9, 8840.0e-9}; + double[] rfInRockSalt = {1.893, 1.544, 1.534, 1.530, 1.526, 1.523, 1.516, 1.502}; + double[] derivRockSalt = {0, 3.74404e+012, -8.62356e+011, 1.19054e+011, -3.00122e+010, 5.3764e+009, -2.20178e+009, 0}; + double refrIndReal, refrIndNacl20, refInWater, reInRockSalt, reInRockSalt5893; + double riWater20_589, moleFractNacl, moleFractWater; + double densityNacl, densityWater, densityWater20, refrIncr; + double n2, lor1, prelor1, a1, b1; + double refrInd, molesWater, molesNacl, lorDens, concen; + int nRi=97, nRockSalt=8; + + concen=concentration*Saline.MOLWEIGHT; + + //calculate the refractive index of pure water at the chosen temperature and wavelength + refInWater=Water.refractIndex(wavelength, temperature); + + if(concentration==0.0){ + refrInd = refInWater; + } + else{ + // calculate refractive increment + + // check limits + if(wavelength<404.6e-9 || wavelength>706.52e-9){ + throw new IllegalArgumentException("Wavelength outside the experimental data limits (404.6nm - 706.52nm)"); + } + else + { + if(temperature<0.0 || temperature>100.0){ + throw new IllegalArgumentException("Temperature " + temperature + " is outside the experimental data limits (0 C - 100 C)"); + } + else + { + if(concen<naclConcRi[0] || concen>naclConcRi[nRi-1]){ + throw new IllegalArgumentException("Concentration" + concen + " is outside the experimental data limits"); + } + else{ + //calculate refractive index of salt solution at 20C and 589.3 + refrIndNacl20=CubicSpline.interpolate(concen, naclConcRi, rfIn, deriv); + } + } + } + + //calculate density of the salt solution at 20C + densityNacl = Saline.density(concentration); + + //density water at 20C + densityWater20=Water.density(20.0); + + //calculate density of water at chosen temperature + densityWater = Water.density(temperature); + + //calculate refractive index of water at 20C at wavelength 589.3nm + riWater20_589=Water.refractIndex(589.3e-9, 20.0); + + //calculate mole fractions + molesWater = (densityNacl*1000 - concen)/Water.MOLWEIGHT; + molesNacl=concentration; + moleFractWater=molesWater/(molesWater + molesNacl); + moleFractNacl=molesNacl/(molesWater + molesNacl); + + //refractive increment + prelor1=(Water.MOLWEIGHT*moleFractWater + Saline.MOLWEIGHT*moleFractNacl); + n2=refrIndNacl20*refrIndNacl20; + refrIncr=((n2-1.0)/(n2+2.0))*prelor1/densityNacl; + + n2=riWater20_589*riWater20_589; + refrIncr-=(((n2-1.0)/(n2+2.0))*(Water.MOLWEIGHT*moleFractWater)/densityWater20); + + //refractive index of rock salt at 589.3nm + reInRockSalt5893=1.516; + + //calculate refractive index of rock salt at correct wavelength + if(wavelength>=wavlRockSalt[0] && wavelength<=wavlRockSalt[nRockSalt-1]){ + reInRockSalt=CubicSpline.interpolate(wavelength, wavlRockSalt, rfInRockSalt, derivRockSalt); + } + else{ + a1=0.515533; + b1=2.50204e-14; + reInRockSalt=1.0+a1*(1.0+b1/Math.pow(wavelength,2)); + } + + //scale refractive increment for wavelength + reInRockSalt *= reInRockSalt; + reInRockSalt5893 *= reInRockSalt5893; + refrIncr = refrIncr*((reInRockSalt-1.0)/(reInRockSalt+2.0))/((reInRockSalt5893-1.0)/(reInRockSalt5893+2.0)); + + //add refractive increment to Lorenz-Lorentz term for water for correct temperature and wavelength + n2=refInWater*refInWater; + lor1=(n2-1.0)/(n2+2.0)*(Water.MOLWEIGHT*moleFractWater)/densityWater; + lor1=lor1+refrIncr; + lorDens=(Water.MOLWEIGHT*moleFractWater*densityWater20/densityWater + Saline.MOLWEIGHT*moleFractNacl)*densityNacl/prelor1; + lor1=(lor1/prelor1)*lorDens; + lor1=(2.0*lor1 + 1.0)/(1.0 - lor1); + refrInd=Math.sqrt(lor1); + } + return refrInd; + } + + // Returns the refractive index of sucrose solutions as a function of g/l sucrose concentration + // Wavelength - sodium D line 589.3 nm + // Interpolation - natural cubic spline + // Extrapolation above 1208.2g/l Lorenz-lorenz equation based on + // average refraction of sucrose calculated from experimental data + // Data - Rubber Handbook + public static double sucrose(double concentration, double temperature){ + double[] concnG = {0, 5, 10, 15.1, 20.1, 25.2, 30.3, 35.4, 40.6, 45.7, 50.9, 56.1, 61.3, 66.5, 71.8, 77.1, 82.4, 87.7, 93.1, 98.4, 103.8, 114.7, 125.6, 136.6, 147.7, 158.9, 170.2, 181.5, 193, 204.5, 216.2, 239.8, 263.8, 288.1, 312.9, 338.1, 363.7, 389.8, 416.2, 443.2, 470.6, 498.4, 526.8, 555.6, 584.9, 614.8, 645.1, 676, 707.4, 739.3, 771.9, 804.9, 838.6, 872.8, 907.6, 943.1, 979.1, 1015.7, 1053, 1090.9, 1129.4, 1168.5, 1208.2}; + double[] refInd = {1.333, 1.3337, 1.3344, 1.3351, 1.3359, 1.3366, 1.3373, 1.3381, 1.3388, 1.3395, 1.3403, 1.341, 1.3418, 1.3425, 1.3433, 1.344, 1.3448, 1.3455, 1.3463, 1.3471, 1.3478, 1.3494, 1.3509, 1.3525, 1.3541, 1.3557, 1.3573, 1.3589, 1.3606, 1.3622, 1.3639, 1.3672, 1.3706, 1.3741, 1.3776, 1.3812, 1.3848, 1.3885, 1.3922, 1.396, 1.3999, 1.4038, 1.4078, 1.4118, 1.4159, 1.4201, 1.4243, 1.4286, 1.433, 1.4374, 1.4419, 1.4465, 1.4511, 1.4558, 1.4606, 1.4654, 1.4703, 1.4753, 1.4803, 1.4854, 1.4906, 1.4958, 1.501}; + double[] deriv = {0, 8.87219e-007, -3.54887e-006, 9.95698e-006, -9.31221e-006, 3.62993e-007, 7.86024e-006, -8.73591e-006, 1.22853e-006, 7.05021e-006, -9.99082e-006, 1.07237e-005, -1.07147e-005, 9.94585e-006, -1.0411e-005, 1.03381e-005, -9.58168e-006, 6.62868e-006, 9.93569e-007, -7.60108e-006, 5.46568e-006, -3.1357e-006, 2.02704e-006, -6.87809e-007, 2.17409e-008, -9.4373e-008, -3.16995e-007, 1.36235e-006, -1.83846e-006, 1.45463e-006, -7.98314e-007, 2.76693e-007, 1.46498e-007, -2.71393e-007, 2.2853e-007, -2.28325e-007, 1.58047e-007, -1.40698e-007, 3.72197e-008, 1.21286e-007, -1.69002e-007, 1.09589e-007, -1.50555e-007, 8.24317e-008, 3.46254e-008, -1.10233e-007, 3.66531e-008, 6.86736e-008, -1.23453e-007, 9.23933e-009, 1.0371e-007, -1.74702e-007, 7.44894e-008, 3.92428e-008, -1.41903e-007, 6.38698e-008, 3.62013e-008, -1.24325e-007, 4.47083e-008, 2.66887e-008, -7.19672e-008, -5.86665e-008, 0}; + double refind, refind2, refind3, sucvol, refracttot, refractwat, refractsuc=0.331335; + double[] weight={5, 10, 15, 20, 30, 40, 50, 60, 70, 75}; + double[][] cf={{-0.25,-0.27,-0.31,-0.31,-0.34,-0.35,-0.36,-0.37,-0.36,-0.36},{-0.21,-0.23,-0.26,-0.27,-0.29,-0.31,-0.31,-0.32,-0.31,-0.29},{-0.16,-0.18,-0.2,-0.2,-0.22,-0.23,-0.23,-0.23,-0.2,-0.17},{-0.11,-0.12,-0.14,-0.14,-0.15,-0.16,-0.16,-0.15,-0.12,-0.09},{-0.06,-0.07,-0.08,-0.08,-0.08,-0.09,-0.09,-0.08,-0.07,-0.05},{0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0},{0.06,0.07,0.07,0.07,0.07,0.07,0.07,0.07,0.07,0.07},{0.12,0.14,0.14,0.14,0.14,0.14,0.15,0.14,0.14,0.14},{0.18,0.2,0.2,0.21,0.21,0.21,0.23,0.21,0.22,0.22},{0.24,0.26,0.26,0.27,0.28,0.28,0.3,0.28,0.29,0.29},{0.3,0.32,0.32,0.34,0.36,0.36,0.38,0.36,0.36,0.37},{0.36,0.39,0.39,0.41,0.43,0.43,0.46,0.44,0.43,0.44},{0.43,0.46,0.46,0.48,0.5,0.51,0.55,0.52,0.5,0.51},{0.5,0.53,0.53,0.55,0.58,0.59,0.63,0.6,0.57,0.59},{0.57,0.6,0.61,0.62,0.66,0.67,0.71,0.68,0.65,0.67},{0.64,0.67,0.7,0.71,0.74,0.75,0.8,0.76,0.73,0.75}}; + double[][] corrfac = new double[16][10]; + double[] tempw = {15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30}; + double[] corrfac5 = {-0.25,-0.21,-0.16,-0.11,-0.06,0.0,0.06,0.12,0.18,0.24,0.3,0.36,0.43,0.5,0.57,0.64}; + double[] derivcor = {0, 0.0157677, -0.00307078, -0.00348457, 0.017009, -0.00455161, 0.00119739, -0.00023797, -0.000245514, 0.00122003, -0.0046346, 0.0173184, -0.00463885, 0.00123703, -0.000309256, 0}; + double concg, concw, corrfactor; + double wavelength = 5.893e-7; + int i,j, m, n=63; + + for(i=0; i<16; i++){ + for(j=0; j<10; j++)corrfac[i][j]=cf[i][j]; + } + + if(concentration>=concnG[0] && concentration<=concnG[n-1]){ + refind=CubicSpline.interpolate(concentration, concnG, refInd, deriv); + } + else{ + refractwat=(refInd[0]*refInd[0]-1.0)/(refInd[0]*refInd[0]+2.0); + sucvol=concentration*Sucrose.specificVolume(concentration)*1e3; + refracttot=(refractsuc*sucvol+refractwat*(1e3-sucvol))/1e3; + refind=(1.0+2.0*refracttot)/(1.0-refracttot); + } + + if(temperature!=20.0){ + concw=Sucrose.gperlToWeightpercent(concentration, temperature); + if(concw<5.0){ + refind2 = Water.refractIndex(wavelength, temperature); + if(concentration==0.0){ + refind=refind2; + } + else{ + corrfactor=CubicSpline.interpolate(temperature, tempw, corrfac5, derivcor); + concw=concw+corrfactor; + concg=Sucrose.weightpercentToGperl(concw, temperature); + refind3=CubicSpline.interpolate(concg, concnG, refInd, deriv); + refind=refind2+(refind3-refind2)*concw/(5.0); + } + } + else{ + BiCubicSpline bcs = new BiCubicSpline(tempw, weight, corrfac); + corrfactor = bcs.interpolate(temperature, concw); + concw=concw+corrfactor; + concg=Sucrose.weightpercentToGperl(concw, temperature); + refind=CubicSpline.interpolate(concg, concnG, refInd, deriv); + } + } + return refind; + } + + // Returns the refractive index of a mixture of material A and material B, + // using the Lorenz-Lorentz equation, given the refractive index of A (na), of B (nb), + // the molecular wight of A (molwta), of B (molwtb), the mole fraction of A (molfracta), + // and the density of A (densa), of B (densb) and of the mixture (densab). + public static double lorenzLorentz(double na, double nb, double molwta, double molwtb, double molfracta, double densa, double densb, double densab){ + double lla, llb, llab, molmassa, molmassb, molmassab, nab; + + molmassa = molfracta*molwta; + molmassb = (1.0 - molfracta)*molwtb; + lla = na*na; + lla = ((lla - 1.0)/(lla + 2.0))*molmassa/densa; + + llb = nb*nb; + llb = ((llb - 1.0)/(llb + 2.0))*molmassb/densb; + + llab = lla + llb; + nab = llab*densab/(molmassa+molmassb); + nab = (2.0*nab + 1.0)/(1.0 - nab); + + return Math.sqrt(nab); + } + + + // Returns the refractive index of a mixture of n materials, + // using the Lorenz-Lorentz equation, given an array of the refractive indices (ni), + // an array of the molecular wights (molwt), an array the mole fractions (molfract), + // and an array of the densities (dens) and the density of the mixture (densmix). + public static double lorenzLorentz(double[] ni, double[] molwt, double[] molfract, double[] dens, double densmix){ + double ll, molmass, nimix, sum0=0, sum1=0.0; + int i, n=ni.length; + + if(n != molwt.length || n != molfract.length || n != dens.length){ + throw new IllegalArgumentException("Array lengths differ"); + } + for(i=0; i<n; i++)sum0+=molfract[i]; + if(Math.abs(1.0-sum0)>1e-5){ + throw new IllegalArgumentException("Mole fractions do not sum to unity"); + } + + sum0=0.0; + for(i=0; i<n; i++){ + molmass = molfract[i]*molwt[i]; + ll = ni[i]*ni[i]; + ll = ((ll - 1.0)/(ll + 2.0))*molmass/dens[i]; + sum0 += ll; + sum1 += molmass; + } + nimix = sum0*densmix/sum1; + nimix = (2.0*nimix + 1.0)/(1.0 - nimix); + + return Math.sqrt(nimix); + } + +} + diff --git a/src/main/java/flanagan/physchem/Donnan.java b/src/main/java/flanagan/physchem/Donnan.java new file mode 100755 index 0000000000000000000000000000000000000000..94fcb506f44666f379a50adc2f2720ca8185f90a --- /dev/null +++ b/src/main/java/flanagan/physchem/Donnan.java @@ -0,0 +1,1496 @@ +/* +* Classes Donnan +* +* Class Donnan contains the primary methods for +* calculating a Donnan Potential between two +* partitions of different electrical permittivity +* (dielectric constant) between which any number of +* ionic species may be partitioned and, in one +* partition only, may bind to a neutral ionophore. +* +* Class Donnan requires Class DonnanMinim and Class DonnanConcn +* that implement interfaces to the required minimisation methods +* +* WRITTEN BY: Michael Thomas Flanagan +* +* DATE: November 2004 +* LAST UPDATE: 1 December 2004, 5-7 July 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Donnan.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) November 2004 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.physchem; + +import java.util.ArrayList; +import flanagan.physprop.IonicRadii; +import flanagan.io.*; +import flanagan.math.*; +import javax.swing.JOptionPane; + +public class Donnan{ + + + private ArrayList<Object> arrayl = new ArrayList<Object>(); // vector holding: + // element 0: name of first ion + // element 1: initial concentration of first ion in partition A (enter as M) + // element 2: initial concentration of first ion in partition B (enter as M) + // element 3: association constant with ionophore (enter as M^-1) + // element 4: radius of first ion (metres) + // element 5: charge of first ion + // element 6: partition coefficient if provided by the user + // -1 if not; partition coefficient to be calculated later + // element 7: name of second ion + // etc + private int numOfIons = 0; // number of ionic species + private int numOfAnions = 0; // number of anionic species + private int numOfCations = 0; // number of cationic species + private String[] ionNames = null; // names of the ions + private double[] concnA = null; // concentration of ions in partition A (moles per cubic metre) + private double[] concnB = null; // concentration of ions in partition B (moles per cubic metre) + private double[] molesT = null; // total moles of an ion + private double[] complex = null; // concentration of complex in partition B (moles per cubic metre) + private double[] excessConcnA = null; // excess concentration of ions in partition A in interfacial charge (moles per cubic metre) + private double[] excessConcnB = null; // excess concentration of ions in partition B in interfacial charge (moles per cubic metre) + private double[] excessComplex = null; // excess concentration of complex in partition B in interfacial charge (moles per cubic metre) + private int[] indexC = null; // ion index of ionic species with non zero total concentrations + private int nonZeroConcns = 0; // number of ionic species with a non-zero total concentration + private double[] assocConsts = null; // association constants of the ions with the ionophore (cubic metres per mole) + private int[] indexK = null; // ion index of ionic species with non zero assocConsts + private int nonZeroAssocK = 0; // number of ionic species with affinity for the ionophore + private double[] radii = null; // radii of ions + private boolean radiusType = true; // if = true - hydrated radii are taken from Class IonicRadii + // if = false - bare radii are taken from Class IonicRadii + private double[] charges = null; // charge of ions + private double tol = 1e-6; // fractional tolerance in checking for overall charge neutrality + // when multiplied by total concentration of species of lowest concentration + // gives limit for considering overall neurtality achieved + private String ionophore = "ionophore"; // name ionophore for output texts + private double ionophoreConcn = 0.0D; // ionophore concentration - entered as molar, converted to moles per cubic metre + private double freeIonophoreConcn = 0.0D; // ionophore concentration - all complex concentrations + private double ionophoreRad = 0.0D; // ionophore radius (metres) + private boolean ionophoreSet = false; // = true when ionophore concentration and radius have been set + private double volumeA = 0.0D; // volume of partition A (cubic metres) + private double volumeB = 0.0D; // volume of partition B (cubic metres) + private double interfacialArea = 0.0D; // onterfacial area between Partitions A and B(square metres) + private boolean volumeSet = false; // = true when volumeA and volumeB have been set + private double epsilonA = 0.0D; // relative electrical permittivity of partition A + private double epsilonB = 0.0D; // relative electrical permittivity of partition B + private double epsilonSternA = 0.0D; // relative electrical permittivity of partition A Stern layer + private double epsilonSternB = 0.0D; // relative electrical permittivity of partition B SternLayer + private boolean epsilonSet = false; // = true when epsilonA and epsilonB have been set + private double temp = 25.0-Fmath.T_ABS; // Temperature (degrees Kelvin) [Enter temperature in degrees Celsius] + private boolean tempSet = false; // = true when temperature has been set + private double[] deltaMu0 = null; // difference in Born charging energy (partitionB - partitionA) + private double[] partCoeff = null; // partition coefficients in absence of inter-partition, e.g. Donnan, potential + private double[] partCoeffPot = null; // partition coefficients in presence of inter-partition, e.g. Donnan, potential + private boolean[] indexPC = null; // partition coefficient (pc) index + // = true if pc provided by user + // = false if pc calculated from Born charging + private double donnanPotential = 0.0D; // Donanan potential with respect to partition A (psiB - psiA) [volts] + private double diffPotentialA = 0.0D; // Double layer potential difference - compartment A [volts] + private double diffPotentialB = 0.0D; // Double layer potential difference - compartment B [volts] + private double sternPotential = 0.0D; // Stern potential difference [volts] + private double estimate = 0.0D; // Initial Estimate of the Donanan potential with respect to partition A (psiB - psiA) [volts] + private double step = 0.0D; // Initial step size in the estimation of the Donanan potential with respect to partition A (psiB - psiA) [volts] + private double tolerance = 1.0e-20; // tolerance in exiting estimation of the Donanan potential with respect to partition A (psiB - psiA) + private int nMaxIter = 10000; // maximum number of iterations allowed in estimation of the Donanan potential with respect to partition A (psiB - psiA) + private int numIterations = 0; // number of iterations taken + private double minimum = 1.0e300; // value of function to be minimised at the minimum + private double sternCap = 0.0D; // Stern layer capacitance [F] + private double diffCapA = 0.0D; // diffuse double layer capacitance in partition A [F] + private double diffCapB = 0.0D; // diffuse double layer capacitance in partition B [F] + private double donnanCap = 0.0D; // total interfacial capacitance [F] + private double sternDeltaA = 0.0D; // Stern layer thickness in partition A [m] + private double sternDeltaB = 0.0D; // Stern layer thickness in partition B [m] + private double chargeValue = 0; // Absolute value of the charge valency if all are the same, i.e. symmetric electrolytes of the same valency + private boolean chargeSame = true; // = false if chargeValue not the same for all ions + private double interfacialChargeDensity = 0.0D;// interface Charge Density [C per square metre] + private double interfacialCharge = 0.0D; // interface Charge [C] + private boolean includeIc = true; // = true - interface charge included in the calculation of the Donnan potential + // = false - interface charge ignored in the calculation of the Donnan Poptential + private double[] ratioA = null; // ratio of excess to bulk concentrations - compartment A + private double[] ratioB = null; // ratio of excess to bulk concentrations - compartment B + private double[] ratioC = null; // ratio of excess to bulk concentrations - complex + private double recipKappaA = 0.0D; // Debye length - compartment A + private double recipKappaB = 0.0D; // Debye length - compartment B + + // Constructor + public Donnan(){ + } + + // Method for setting ionic radii taken from Class IonicRadii to hydrated radii + // This is the default option + public void setHydratedRadii(){ + this.radiusType = true; + } + + // Method for setting ionic radii taken from Class IonicRadii to bare radii + public void setBareRadii(){ + this.radiusType = false; + } + + // Method for setting Donnan Potential calculatiom method to ignore interfacial charge + public void ignoreInterfaceCharge(){ + this.includeIc = false; + } + + // Method for setting Donnan Potential calculatiom method to include interfacial charge + // This is the default option + public void includeInterfaceCharge(){ + this.includeIc = true; + } + + + // Method to add an ionic species to the Donnan Equilibrium + // Partition coefficient to be calculated from Born charging equation + // Concentrations - Molar, assocK - M^-1, radius - metres, charge - valency e.g. +1 + public void setIon(String ion, double concnA, double concnB, double assocK, double radius, int charge){ + this.arrayl.add(ion); + this.arrayl.add(new Double(concnA)); + this.arrayl.add(new Double(concnB)); + if(concnA>0.0D || concnB>0.0)this.nonZeroConcns++; + this.arrayl.add(new Double(assocK)); + if(assocK!=0.0D)this.nonZeroAssocK++; + this.arrayl.add(new Double(radius)); + this.arrayl.add(new Integer(charge)); + this.arrayl.add(new Double(-1.0D)); + this.numOfIons++; + } + + // Method to add an ionic species to the Donnan Equilibrium + // Partition coefficient supplied by user + // Concentrations - Molar, assocK - M^-1, radius - metres, charge - valency e.g. +1 + public void setIon(double partCoeff, String ion, double concnA, double concnB, double assocK, double radius, int charge){ + this.arrayl.add(ion); + this.arrayl.add(new Double(concnA)); + this.arrayl.add(new Double(concnB)); + if(concnA>0.0D || concnB>0.0)this.nonZeroConcns++; + this.arrayl.add(new Double(assocK)); + if(assocK!=0.0D)this.nonZeroAssocK++; + this.arrayl.add(new Double(radius)); + this.arrayl.add(new Integer(charge)); + this.arrayl.add(new Double(partCoeff)); + this.numOfIons++; + } + + // Method to add an ionic species to the Donnan Equilibrium + // Partition coefficient to be calculated from Born charging equation + // Concentrations - Molar, radius - metres, charge - valency e.g. +1 + // association constant = 0.0D + public void setIon(String ion, double concnA, double concnB, double radius, int charge){ + this.arrayl.add(ion); + this.arrayl.add(new Double(concnA)); + this.arrayl.add(new Double(concnB)); + if(concnA>0.0D || concnB>0.0)this.nonZeroConcns++; + this.arrayl.add(new Double(0.0D)); + this.arrayl.add(new Double(radius)); + this.arrayl.add(new Integer(charge)); + this.arrayl.add(new Double(-1.0D)); + this.numOfIons++; + } + + // Method to add an ionic species to the Donnan Equilibrium + // Partition coefficient to be supplied by user + // Concentrations - Molar, radius - metres, charge - valency e.g. +1 + // association constant = 0.0D + public void setIon(double partCoeff, String ion, double concnA, double concnB, double radius, int charge){ + this.arrayl.add(ion); + this.arrayl.add(new Double(concnA)); + this.arrayl.add(new Double(concnB)); + if(concnA>0.0D || concnB>0.0)this.nonZeroConcns++; + this.arrayl.add(new Double(0.0D)); + this.arrayl.add(new Double(radius)); + this.arrayl.add(new Integer(charge)); + this.arrayl.add(new Double (partCoeff)); + this.numOfIons++; + } + + // Method to add an ionic species to the Donnan Equilibrium + // Partition coefficient to be calculated from Born charging equation + // default radii and charge taken from class IonicRadii + // if radii not in Ionic Radii, Donnan potential calculated with interface charge neglected + // Concentrations - Molar + public void setIon(String ion, double concnA, double concnB, double assocK){ + IonicRadii ir = new IonicRadii(); + this.arrayl.add(ion); + this.arrayl.add(new Double(concnA)); + this.arrayl.add(new Double(concnB)); + if(concnA>0.0D || concnB>0.0)this.nonZeroConcns++; + this.arrayl.add(new Double(assocK)); + if(assocK!=0.0D)this.nonZeroAssocK++; + double rad = 0.0D; + if(this.radiusType){ + rad = ir.hydratedRadius(ion); + } + else{ + rad = ir.radius(ion); + } + + if(rad==0.0D){ + String mess1 = ion + " radius is not in the IonicRadii list\n"; + String mess2 = "Please enter radius in metres\n"; + rad = Db.readDouble(mess1+mess2); + } + this.arrayl.add(new Double(rad)); + int charg = 0; + charg = ir.charge(ion); + if(charg==0){ + String mess1 = ion + " charge is not in the IonicRadii list\n"; + String mess2 = "Please enter charge, e.g +2"; + charg = Db.readInt(mess1+mess2); + } + this.arrayl.add(new Integer(charg)); + this.arrayl.add(new Double(-1.0D)); + this.numOfIons++; + } + + // Method to add an ionic species to the Donnan Equilibrium + // Partition coefficient to be supplied by user + // default radii and charge taken from class IonicRadii + // Concentrations - Molar + public void setIon(double partCoeff, String ion, double concnA, double concnB, double assocK){ + IonicRadii ir = new IonicRadii(); + this.arrayl.add(ion); + this.arrayl.add(new Double(concnA)); + this.arrayl.add(new Double(concnB)); + if(concnA>0.0D || concnB>0.0)this.nonZeroConcns++; + this.arrayl.add(new Double(assocK)); + if(assocK!=0.0D)this.nonZeroAssocK++; + double rad = 0.0D; + if(this.includeIc){ + if(this.radiusType){ + rad = ir.hydratedRadius(ion); + } + else{ + rad = ir.radius(ion); + } + + if(rad==0.0D){ + String mess1 = ion + " radius is not in the IonicRadii list\n"; + String mess2 = "Please enter radius in metres\n"; + String mess3 = "Enter 0.0 if you wish interfacial charge to be neglected"; + rad = Db.readDouble(mess1+mess2+mess3); + if(rad==0.0D)this.includeIc = false; + } + } + this.arrayl.add(new Double(rad)); + int charg = 0; + charg = ir.charge(ion); + if(charg==0){ + String mess1 = ion + " charge is not in the IonicRadii list\n"; + String mess2 = "Please enter charge, e.g +2"; + charg = Db.readInt(mess1+mess2); + } + this.arrayl.add(new Integer(charg)); + this.arrayl.add(new Double(partCoeff)); + this.numOfIons++; + } + + // Method to add an ionic species to the Donnan Equilibrium + // Partition coefficients to be calculated from Born charging equation + // default radii and charge taken from class IonicRadii + // association constant = 0.0D + // Concentrations - Molar + public void setIon(String ion, double concnA, double concnB){ + IonicRadii ir = new IonicRadii(); + this.arrayl.add(ion); + this.arrayl.add(new Double(concnA)); + this.arrayl.add(new Double(concnB)); + if(concnA>0.0D || concnB>0.0)this.nonZeroConcns++; + this.arrayl.add(new Double(0.0D)); + double rad = 0.0D; + if(this.radiusType){ + rad = ir.hydratedRadius(ion); + } + else{ + rad = ir.radius(ion); + } + if(rad==0.0D){ + String mess1 = ion + " radius is not in the IonicRadii list\n"; + String mess2 = "Please enter radius in metres\n"; + rad = Db.readDouble(mess1+mess2); + if(rad==0.0D)this.includeIc = false; + } + this.arrayl.add(new Double(rad)); + int charg = 0; + charg = ir.charge(ion); + if(charg==0){ + String mess1 = ion + " charge is not in the IonicRadii list\n"; + String mess2 = "Please enter charge, e.g +2"; + charg = Db.readInt(mess1+mess2); + } + this.arrayl.add(new Integer(charg)); + this.arrayl.add(new Double(-1.0D)); + this.numOfIons++; + } + + // Method to add an ionic species to the Donnan Equilibrium + // Partition coefficients to be supplied by the user + // default radii and charge taken from class IonicRadii + // association constant = 0.0D + // Concentrations - Molar + public void setIon(double partCoeff, String ion, double concnA, double concnB){ + IonicRadii ir = new IonicRadii(); + this.arrayl.add(ion); + this.arrayl.add(new Double(concnA)); + this.arrayl.add(new Double(concnB)); + if(concnA>0.0D || concnB>0.0)this.nonZeroConcns++; + this.arrayl.add(new Double(0.0D)); + double rad = 0.0D; + if(this.includeIc){ + if(this.radiusType){ + rad = ir.hydratedRadius(ion); + } + else{ + rad = ir.radius(ion); + } + + if(rad==0.0D){ + String mess1 = ion + " radius is not in the IonicRadii list\n"; + String mess2 = "Please enter radius in metres\n"; + String mess3 = "Enter 0.0 if you wish interfacial charge to be neglected"; + rad = Db.readDouble(mess1+mess2+mess3); + if(rad==0.0D)this.includeIc = false; + } + } + this.arrayl.add(new Double(rad)); + int charg = 0; + charg = ir.charge(ion); + if(charg==0){ + String mess1 = ion + " charge is not in the IonicRadii list\n"; + String mess2 = "Please enter charge, e.g +2"; + charg = Db.readInt(mess1+mess2); + } + this.arrayl.add(new Integer(charg)); + this.arrayl.add(new Double(partCoeff)); + this.numOfIons++; + } + + // Method to add an ionophore to the partition B + // Concentration = Molar, radius = metres + public void setIonophore(double concn, double radius){ + this.ionophoreConcn = concn*1e3; + this.ionophoreRad = radius; + this.ionophoreSet = true; + } + + // Method to add an ionophore to the partition B + // Concentration = Molar, radius = metres + // Ionophore name can be added for output text + public void setIonophore(String ionophore, double concn, double radius){ + this.ionophore = ionophore; + this.ionophoreConcn = concn*1e3; + this.ionophoreRad = radius; + this.ionophoreSet = true; + } + + // Method to add an ionophore to the partition B + // No radius added - calculation of Donnan potential will neglect interface charge + // Concentration = Molar + // Ionophore name can be added for output text + public void setIonophore(String ionophore, double concn){ + this.ionophore = ionophore; + this.ionophoreConcn = concn*1e3; + this.includeIc = false; + this.ionophoreSet = true; + } + + // Method to add an ionophore to the partition B + // No radius added - calculation of Donnan potential will neglect interface charge + // Concentration = Molar + public void setIonophore(double concn){ + this.ionophoreConcn = concn*1e3; + this.includeIc = false; + this.ionophoreSet = true; + } + + // Method to set partition volumes (m^3) and interfacial area + public void setVolumes(double volA, double volB, double area){ + this.volumeA = volA; + this.volumeB = volB; + this.interfacialArea = area; + this.volumeSet = true; + } + + // Method to set partition volumes (m^3) + // No interfacial area entered - calculation of Donnan potential will neglect interface charge + public void setVolumes(double volA, double volB){ + this.volumeA = volA; + this.volumeB = volB; + this.includeIc = false; + this.volumeSet = true; + } + + // Method to set partition relative permittivities + public void setRelPerm(double epsA, double epsB, double epsSternA, double epsSternB){ + this.epsilonA = epsA; + this.epsilonB = epsB; + this.epsilonSternA = epsSternA; + this.epsilonSternB = epsSternB; + this.epsilonSet = true; + } + + // Method to set partition relative permittivities + // No Stern layer permittivities included - interface charge cannot be calculated + public void setRelPerm(double epsA, double epsB){ + this.epsilonA = epsA; + this.epsilonB = epsB; + this.includeIc = false; + this.epsilonSet = true; + } + + // Method to set temperature (enter as degrees Celsius) + public void setTemp(double temp){ + this.temp = temp - Fmath.T_ABS; + this.tempSet = true; + } + + // Method to set initial estimate of the Donnan potential (V) + public void setEstimate(double pot){ + this.estimate = pot; + } + + // Method to set initial step size of the Donnan potential Estimations (V) + public void setStep(double step){ + this.step = step; + } + + // Method to set tolerance in exiting the Donnan potential calculation + public void setTolerance(double tol){ + this.tolerance = tol; + } + + // Method to set maximum number of iterations in calculating the Donnan potential calculation + public void setMaxIterations(int nMax){ + this.nMaxIter = nMax; + } + + // Method to get the Donnan potential [volts] + public double getDonnanPotential(){ + return this.donnanPotential; + } + + // Method to get the diffuse double layer potential in partition A [volts] + public double getDiffuseLayerPotentialA(){ + return this.diffPotentialA; + } + + // Method to get the diffuse double layer potential in partition B [volts] + public double getDiffuseLayerPotentialB(){ + return this.diffPotentialB; + } + + // Method to get the Stern layer potential [volts] + public double getSternLayerPotential(){ + return this.sternPotential; + } + + // Method to get the bulk concentrations of the ionic species, in partition A, at the minimum [M] + public double[] getConcnA(){ + double[] concn = this.concnA.clone(); + for(int i=0; i<this.numOfIons; i++)concn[i] *= 1e-3; + return concn; + } + + // Method to get the bulk concentrations of the ionic species, in partition B, at the minimum [M] + public double[] getConcnB(){ + double[] concn = this.concnB.clone(); + for(int i=0; i<this.numOfIons; i++)concn[i] *= 1e-3; + return concn; + } + + // Method to get the bulk concentrations of the complex species, in partition B, at the minimum [M] + public double[] getComplex(){ + double[] concn = this.complex.clone(); + for(int i=0; i<this.numOfIons; i++)concn[i] *= 1e-3; + return concn; + } + + // Method to get the excess concentrations of the ionic species, in partition A, at the minimum [M] + public double[] getExcessConcnA(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getExcessConcnA\nThe values of the excess concentrations have not been calculated\nzeros returned"); + } + double[] concn = this.excessConcnA.clone(); + for(int i=0; i<this.numOfIons; i++)concn[i] *= 1e-3; + return concn; + } + + // Method to get the excessConcentrations of the ionic species, in partition B, at the minimum [M] + public double[] getExcessConcnB(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getExcessConcnA\nThe values of the excess concentrations have not been calculated\nzeros returned"); + } + double[] concn = this.excessConcnB.clone(); + for(int i=0; i<this.numOfIons; i++)concn[i] *= 1e-3; + return concn; + } + + // Method to get the excess concentrations of the complex species, in partition B, at the minimum [M] + public double[] getExcessComplex(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getExcessConcnA\nThe values of the excess concentrations have not been calculated\nzeros returned"); + } + double[] concn = this.excessComplex.clone(); + for(int i=0; i<this.numOfIons; i++)concn[i] *= 1e-3; + return concn; + } + + // Method to get the ratio of excess concentrations over bulk concentrations of the ionic in partition A + public double[] getRatioA(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getRatioA\nThe values of the excess to bulk concentrations have not been calculated\nzeros returned"); + } + return this.ratioA; + } + + // Method to get the ratio of excess concentrations over bulk concentrations of the ionic but not complex species, in partition B + public double[] getRatioB(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getRatioB\nThe values of the excess to bulk concentrations have not been calculated\nzeros returned"); + } + return this.ratioB; + } + + // Method to get the ratio of excess concentrations over bulk concentrations of the complex species + public double[] getRatioComplex(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getRatioComplex\nThe values of the excess to bulk concentrations have not been calculated\nzeros returned"); + } + return this.ratioC; + } + + // Method to get the partition coefficients at equilibrium + public double[] getPartitionCoefficients(){ + return this.partCoeffPot; + } + + // Method to get the partition coefficients in the absence of a Donnan Potential + public double[] getPartitionCoefficientsZero(){ + return this.partCoeff; + } + + // Method to get the difference in Born Charging energy between partitions A and B + public double[] getDeltaMu0(){ + return this.deltaMu0; + } + + // Method to get the total interfacial charge + public double getInterfaceCharge(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getInterfaceCharge\nThe value of the interface charge has not been calculated\nzero returned"); + } + return this.interfacialCharge; + } + + // Method to get the interfacial charge density + public double getInterfaceChargeDensity(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getInterfaceChargeDensity\nThe value of the interface charge density has not been calculated\nzero returned"); + } + return this.interfacialCharge; + } + + // Method to get the Stern Capacitance + public double getSternCapacitance(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getSternCapacitance\nThe value of the Stern capacitance has not been calculated\nzero returned"); + } + return this.sternCap*this.interfacialArea; + } + + + // Method to get the diffuse layer Capacitance in Partition A + public double getDiffuseLayerCapacitanceA(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getDiffuseLayerCapacitanceA\nThe values of the diffuse layer capacitances have not been calculated\nzero returned"); + } + return this.diffCapA*this.interfacialArea; + } + + + // Method to get the diffuse layer Capacitance in Partition B + public double getDiffuseLayerCapacitanceB(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getDiffuseLayerCapacitanceB\nThe values of the diffuse layer capacitances have not been calculated\nzero returned"); + } + return this.diffCapB*this.interfacialArea; + } + + // Method to get the Donnan Capacitance + public double getDonnanCapacitanceB(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getDonnanCapacitance\nThe value of the Donnan capacitance has not been calculated\nzero returned"); + } + return this.donnanCap*this.interfacialArea; + } + + // Method to get the Stern layer thickness in Partition A + public double getSternThicknessA(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getSternThicknessA\nThe values of the Stern layer thicknesses have not been calculated\nzero returned"); + } + return this.sternDeltaA; + } + + // Method to get the Stern layer thickness in Partition B + public double getSternThicknessB(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getSternThicknessB\nThe values of the Stern layer thicknesses have not been calculated\nzero returned"); + } + return this.sternDeltaB; + } + + // Method to get the Debye length in Partition A + public double getDebyeLengthA(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getDebyeLengthA\nThe values of the Debye lengths have not been calculated\nzero returned"); + } + return this.recipKappaA; + } + + // Method to get the Debye length in Partition A + public double getDebyeLengthB(){ + if(!this.includeIc){ + System.out.println("Class: Donnan\nMethod: getDebyeLengthB\nThe values of the Debye lengths have not been calculated\nzero returned"); + } + return this.recipKappaB; + } + + // Method to get the minimised function (square of charge in B) value at the minimum + public double getMinimum(){ + return this.minimum; + } + + // Method to calculate the Donnan potential (V) + public double calcPotential(){ + // check all information needed is present and check overall charge neutrality + unpack(); + + // Repack to eliminate zero concentration ions + double numOfIonsHold = this.numOfIons; + double[] assocConstshold = null; + double[] radiihold = null; + double[] chargeshold = null; + double[] deltaMu0hold = null; + double[] partCoeffhold = null; + + if(this.nonZeroConcns<this.numOfIons){ + assocConstshold = this.assocConsts.clone(); + radiihold = this.radii.clone(); + chargeshold = this.charges.clone(); + deltaMu0hold = this.deltaMu0.clone(); + partCoeffhold = this.partCoeff.clone(); + boolean test = true; + int jj = 0; + while(test){ + if(indexC[jj]==0){ + for(int k=jj+1; k<this.numOfIons; k++){ + this.concnA[k-1] = this.concnA[k]; + this.concnB[k-1] = this.concnB[k]; + this.complex[k-1] = this.complex[k]; + this.molesT[k-1] = this.molesT[k]; + this.assocConsts[k-1] = this.assocConsts[k]; + this.radii[k-1] = this.radii[k]; + this.charges[k-1] = this.charges[k]; + this.deltaMu0[k-1] = this.deltaMu0[k]; + this.partCoeff[k-1] = this.partCoeff[k]; + } + this.numOfIons--; + } + else{ + jj++; + } + if(this.numOfIons==this.nonZeroConcns)test=false; + } + } + + // Obtain Donnan potential by miminimising + // the square of the net charge in partition B + + // Check if interface charge is to be include + // if it is - perform calculation first without interface charge + // to obtain workable initial estimates for calculation with interface charge included + boolean includeIcHold = false; + if(this.includeIc){ + includeIcHold = true; + this.includeIc = false; + } + + //Create instance of Minimisation + Minimisation minPot = new Minimisation(); + + // Create instace of class holding function to be minimised + DonnanMinim functD = new DonnanMinim(this.numOfIons); + + // Initialise function functD variable + + functD.numOfIons = this.numOfIons; + functD.concnA = this.concnA; + functD.concnB = this.concnB; + functD.molesT = this.molesT; + functD.complex = this.complex; + functD.excessConcnA = this.excessConcnA; + functD.excessConcnB = this.excessConcnB; + functD.excessComplex = this.excessComplex; + functD.assocConsts = this.assocConsts; + functD.indexK = this.indexK; + functD.nonZeroAssocK = this.nonZeroAssocK; + functD.radii = this.radii; + functD.charges = this.charges; + functD.ionophoreConcn = this.ionophoreConcn; + functD.ionophoreRad = this.ionophoreRad; + functD.volumeA = this.volumeA; + functD.volumeB = this.volumeB; + functD.interfacialArea = this.interfacialArea; + functD.epsilonA = this.epsilonA; + functD.epsilonB = this.epsilonB; + functD.epsilonSternA = this.epsilonSternA; + functD.epsilonSternB = this.epsilonSternB; + functD.temp = this.temp; + functD.partCoeff = this.partCoeff; + functD.partCoeffPot = this.partCoeffPot; + functD.sternCap = this.sternCap; + functD.sternDeltaA = this.sternDeltaA; + functD.sternDeltaB = this.sternDeltaB; + functD.chargeValue = this.chargeValue; + functD.chargeSame = this.chargeSame; + functD.interfacialCharge = this.interfacialCharge; + functD.interfacialChargeDensity = this.interfacialChargeDensity; + functD.includeIc = this.includeIc; + + + // initial estimate + double[] start = {this.estimate}; + // initial step size + double[] step = {this.step}; + + // Nelder and Mead minimisation procedure + minPot.nelderMead(functD, start, step, this.tolerance, this.nMaxIter); + + // get values of the Donnan potential at minimum + double[] param = minPot.getParamValues(); + this.donnanPotential = param[0]; + + // Repeat with interface charge included if this is required + if(includeIcHold){ + this.includeIc = true; + + // initial estimate + start[0] = this.donnanPotential; + // initial step size + step[0] = this.step; + + // Nelder and Mead minimisation procedure + minPot.nelderMead(functD, start, step, this.tolerance, this.nMaxIter); + + // get values of the Donnan potential at minimum + param = minPot.getParamValues(); + this.donnanPotential = param[0]; + } + + // Calculate concentartions at the minimum + ionConcns(this.donnanPotential); + + // Repack if zero concentration ions were present + if(this.nonZeroConcns!=numOfIonsHold){ + boolean test = true; + int jj = 0; + while(test){ + if(indexC[jj]==0){ + for(int k=jj; k<this.numOfIons; k++){ + this.concnA[k+1] = this.concnA[k]; + this.concnB[k+1] = this.concnB[k]; + this.complex[k+1] = this.complex[k]; + this.excessConcnA[k+1] = this.excessConcnA[k]; + this.excessConcnB[k+1] = this.excessConcnB[k]; + this.excessComplex[k+1] = this.excessComplex[k]; + this.molesT[k+1] = this.molesT[k]; + this.assocConsts[k+1] = this.assocConsts[k]; + this.radii[k+1] = this.radii[k]; + this.charges[k+1] = this.charges[k]; + this.deltaMu0[k+1] = this.deltaMu0[k]; + this.partCoeff[k+1] = this.partCoeff[k]; + this.partCoeffPot[k+1] = this.partCoeffPot[k]; + } + this.numOfIons++; + this.concnA[jj] = 0.0D; + this.concnB[jj] = 0.0D; + this.complex[jj] = 0.0D; + this.excessConcnA[jj] = 0.0D; + this.excessConcnB[jj] = 0.0D; + this.excessComplex[jj] = 0.0D; + this.molesT[jj] = 0.0D; + this.assocConsts[jj] = assocConstshold[jj]; + this.radii[jj] = radiihold[jj]; + this.charges[jj] = chargeshold[jj]; + this.deltaMu0[jj] = deltaMu0hold[jj]; + this.partCoeff[jj] = partCoeffhold[jj]; + } + else{ + jj++; + } + if(this.numOfIons==this.nonZeroConcns)test=false; + } + } + + // get the minimum value + this.minimum = minPot.getMinimum(); + + // get the number of iterations + this.numIterations = minPot.getNiter(); + + if(this.includeIc){ + // Calculate excess to bulk ratios + for(int i=0; i<this.numOfIons; i++){ + this.ratioA[i] = this.excessConcnA[i]/this.concnA[i]; + this.ratioB[i] = this.excessConcnB[i]/this.concnB[i]; + this.ratioC[i] = this.excessComplex[i]/this.complex[i]; + } + + // Calculate overall and diffuse layer capacitances + this.diffCapA = this.interfacialCharge/this.diffPotentialA; + this.diffCapB = this.interfacialCharge/this.diffPotentialB; + this.donnanCap = this.interfacialCharge/this.donnanPotential; + + // Calculate Debye lengths + double preterm = 2.0D*Fmath.square(Fmath.Q_ELECTRON)*Fmath.N_AVAGADRO/(Fmath.EPSILON_0*Fmath.K_BOLTZMANN*this.temp); + double pretermA = preterm/this.epsilonA; + double pretermB = preterm/this.epsilonB; + this.recipKappaA = 0.0; + this.recipKappaB = 0.0; + for(int i=0; i<this.numOfIons; i++){ + this.recipKappaA += this.concnA[i]*charges[i]*charges[i]; + this.recipKappaB += (this.concnB[i] + this.complex[i])*charges[i]*charges[i]; + } + this.recipKappaA = 1.0D/Math.sqrt(this.recipKappaA*pretermA); + this.recipKappaB = 1.0D/Math.sqrt(this.recipKappaB*pretermB); + + // Calculate deltaMu0s for user supplied partition coefficients + // and scale all deltaMu0s to per mole + for(int ii=0; ii<this.numOfIons; ii++){ + if(this.indexPC[ii]){ + this.deltaMu0[ii] = Math.log(this.partCoeff[ii])*(Fmath.N_AVAGADRO*Fmath.K_BOLTZMANN)*this.temp; + } + else{ + this.deltaMu0[ii] *= Fmath.N_AVAGADRO; + } + } + + // Calculate partition coefficients at equilibrium + for(int ii=0; ii<this.numOfIons; ii++){ + this.partCoeffPot[ii] = this.partCoeff[ii]*Math.exp((-this.donnanPotential*this.charges[ii]*Fmath.Q_ELECTRON)/(Fmath.K_BOLTZMANN*this.temp)); + } + + } + + return this.donnanPotential; + } + + // Unpacks the ion storage ArrayList and fills the appropriate arrays + // Checks all relevant data has been entered + private void unpack(){ + if(!this.volumeSet)throw new IllegalArgumentException("The volumes of the partitions have not been set"); + if(this.numOfIons==0)throw new IllegalArgumentException("No ions have been entered"); + if(this.nonZeroConcns==0)throw new IllegalArgumentException("No non-zero ionic concentrations have been entered"); + if(!this.epsilonSet)throw new IllegalArgumentException("The relative permittivities of the partitions have not been set"); + if(!this.tempSet)System.out.println("The temperature has not been entered\na value of 25 degrees Celsius has been used"); + if(!this.ionophoreSet){ + System.out.println("The ionophore has not been entered\na concentration value of zero has been used"); + if(this.includeIc){ + this.includeIc=false; + System.out.println("and the interface charge option has been set to neglect the interface charge"); + } + } + + // change concentrations to moles per cubic metre + // fill primitive data arrays + // calculate total moles + // check if the electrolyte is charge symmetric + this.ionNames = new String[this.numOfIons]; + this.concnA = new double[this.numOfIons]; + this.concnB = new double[this.numOfIons]; + this.molesT = new double[this.numOfIons]; + this.complex = new double[this.numOfIons]; + this.excessConcnA = new double[this.numOfIons]; + this.excessConcnB = new double[this.numOfIons]; + this.excessComplex = new double[this.numOfIons]; + this.ratioA = new double[this.numOfIons]; + this.ratioB = new double[this.numOfIons]; + this.ratioC = new double[this.numOfIons]; + this.assocConsts = new double[this.numOfIons]; + this.radii = new double[this.numOfIons]; + this.charges = new double[this.numOfIons]; + this.deltaMu0 = new double[this.numOfIons]; + this.partCoeff = new double[this.numOfIons]; + this.partCoeffPot = new double[this.numOfIons]; + this.indexK = new int[this.nonZeroAssocK]; + this.indexC = new int[this.numOfIons]; + this.indexPC = new boolean[this.numOfIons]; + Double hold = null; + Integer holi = null; + int ii = 0; + this.chargeValue = 0; + this.chargeSame = true; + + for(int i=0; i<numOfIons; i++){ + // ion name + this.ionNames[i]= (String)this.arrayl.get(0+i*7); + // concentration in compartment A + hold = (Double)this.arrayl.get(1+i*7); + this.concnA[i] = hold.doubleValue()*1e3; + hold = (Double)this.arrayl.get(2+i*7); + // concentration in compartment B + this.concnB[i] = hold.doubleValue()*1e3; + // total moles of ion i + this.molesT[i] = this.concnA[i]*volumeA + this.concnB[i]*volumeB; + if(this.molesT[i]>0.0D){ + indexC[i] = 1; + } + else{ + indexC[i] = 0; + } + // association constant + hold = (Double)this.arrayl.get(3+i*7); + this.assocConsts[i] = hold.doubleValue()*1e-3; + if(this.assocConsts[i]>0.0D){ + indexK[ii] = i; + ii++; + } + // ion radius + hold = (Double)this.arrayl.get(4+i*7); + this.radii[i] = hold.doubleValue(); + // ion charge + holi = (Integer)this.arrayl.get(5+i*7); + this.charges[i] = holi.intValue(); + // running check for all ions having same absolute charge + if(i==0){ + this.chargeValue = Math.abs(this.charges[0]); + } + else{ + if(Math.abs(this.charges[i])!=this.chargeValue)this.chargeSame=false; + } + + // partition coefficient + hold = (Double)this.arrayl.get(6+i*7); + this.partCoeff[i]= hold.doubleValue(); + this.indexPC[i] = true; + if(this.partCoeff[i]==-1.0D){ + this.indexPC[i] = false; + // calculate partition coefficient from Born charging equation + // calculate differences in Born charging energies between the two partitions + this.deltaMu0[i] = this.BornChargingEnergy(this.radii[i], this.charges[i], this.epsilonB) - this.BornChargingEnergy(this.radii[i], this.charges[i], this.epsilonA); + + // calculate partition coefficients + this.partCoeff[i] = Math.exp((this.deltaMu0[i])/(Fmath.K_BOLTZMANN*this.temp)); + } + // calculate number of anionic and cationic species + if(charges[i]<0){ + numOfAnions++; + } + else{ + numOfCations++; + } + if(this.ionophoreConcn==0.0D)this.nonZeroAssocK = 0; + } + + + // Calculate overall charge + double overallCharge = 0.0D; + double positives = 0.0D; + double negatives = 0.0D; + for(int i=0; i<numOfIons; i++){ + if(charges[i]>0.0D){ + positives += this.molesT[i]*charges[i]; + } + else{ + negatives += this.molesT[i]*charges[i]; + } + overallCharge = positives + negatives; + } + if(Math.abs(overallCharge)>positives*this.tol){ + String quest0 = "Class: Donnan, method: unpack()\n"; + String quest1 = "Total charge = " + overallCharge + " mol/dm, i.e. is not equal to zero\n"; + String quest2 = "Positive charge = " + positives + " mol/dm\n"; + String quest3 = "Do you wish to continue?"; + String quest = quest0 + quest1 + quest2 + quest3; + int res = JOptionPane.showConfirmDialog(null, quest, "Neutrality check", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if(res==1)System.exit(0); + } + } + + // Calculate Born charging energy + public double BornChargingEnergy(double radius, double charge, double epsilon){ + return Fmath.square(Fmath.Q_ELECTRON*charge)/(8.0*Math.PI*radius*Fmath.EPSILON_0*epsilon); + } + + // Method that calculate partitions A and B and ionophore complex concentrations + // of the iith ion for a given trans partition, e.g. Donnan potential + public void ionConcns(double potential){ + + // calculate partition coefficients for given potential + for(int ii=0; ii<this.numOfIons; ii++){ + this.partCoeffPot[ii] = this.partCoeff[ii]*Math.exp((-potential*this.charges[ii]*Fmath.Q_ELECTRON)/(Fmath.K_BOLTZMANN*this.temp)); + } + + if(!this.includeIc){ + // Interface charge ignored + if(this.nonZeroAssocK<2){ + // Only one or none of the ions with an affinity for the ionophore + calcConcnsSingleK(potential); + } + else{ + // More than one ion competes for the ionophore + + // obtain ionic and complex concentrations for a given Donnan potential + // by miminimising the sum of the squares of the equations describing each equilibrium + calcConcnsMultiK(potential); + } + } + else{ + // interface charge included + + // obtain ionic and complex concentrations for a given Donnan potential + // by miminimising the sum of the squares of the equations describing each equilibrium + calcConcnsMultiK(potential); + } + } + + // Method to calculate ionic concentrations when only one ion or no ions bind to the ionophore + public void calcConcnsSingleK(double potential){ + + for(int ii=0; ii<this.numOfIons; ii++){ + if(this.assocConsts[ii]==0.0D || this.ionophoreConcn==0.0D){ + if(molesT[ii]==0.0D){ + // ion ii not present + this.concnB[ii] = 0.0D; + this.concnA[ii] = 0.0D; + this.complex[ii] = 0.0D; + } + else{ + // No ionophore present or ion ii has no affinity for the ionophore + this.concnB[ii] = this.molesT[ii]/(this.volumeA*this.partCoeffPot[ii] + this.volumeB); + this.concnA[ii] = this.concnB[ii]*this.partCoeffPot[ii]; + this.complex[ii] = 0.0D; + } + } + else{ + // ion ii is the single ionic species with an affinity for the ionophore which is present + // solve quadratic equilibrium equation + // calculate quadratic terms + double aa = this.assocConsts[ii]*(this.volumeB + this.volumeA*this.partCoeffPot[ii]); + double bb = this.volumeB + this.volumeA*this.partCoeffPot[ii] + this.volumeB*this.assocConsts[ii]*ionophoreConcn - this.assocConsts[ii]*this.molesT[ii]; + double cc = -this.molesT[ii]; + // solve quadratic equatiom + double root = bb*bb - 4.0D*aa*cc; + if(root<0.0D){ + System.out.println("Class: DonnanMinim\nMethod: ionConcns\nthe square root term (b2-4ac) of the quadratic = "+root); + System.out.println("this term was set to zero as the negative value MAY have arisen from rounding errors"); + root = 0.0D; + } + double qq = -0.5*(bb + Fmath.sign(bb)*Math.sqrt(root)); + double root1 = qq/aa; + double root2 = cc/qq; + double limit = this.molesT[ii]/(this.volumeA*this.partCoeffPot[ii] + this.volumeB); + if(root1>=0.0D && root1<=limit){ + if(root2<0.0D || root2>limit){ + this.concnB[ii] = root1; + this.concnA[ii] = this.concnB[ii]*this.partCoeffPot[ii]; + this.complex[ii] = this.assocConsts[ii]*this.ionophoreConcn*this.concnB[ii]/(1.0D + this.assocConsts[ii]*this.concnB[ii]); + //this.complex[ii] = (this.molesT[ii] - this.concnA[ii]*this.volumeA - this.concnB[ii]*this.volumeB)/this.volumeB; + } + else{ + System.out.println("Class: DonnanMinim\nMethod: ionConcns"); + System.out.println("error1: no physically meaningfull root"); + System.out.println("root1 = " + root1 + " root2 = " + root2 + " limit = " + limit); + System.exit(0); + } + } + else{ + if(root2>=0.0D && root2<=limit){ + if(root1<0.0D || root1>limit){ + this.concnB[ii] = root2; + this.concnA[ii] = this.concnB[ii]*this.partCoeffPot[ii]; + //this.complex[ii] = (this.molesT[ii] - this.concnA[ii]*this.volumeA - this.concnB[ii]*this.volumeB)/this.volumeB; + this.complex[ii] = this.assocConsts[ii]*this.ionophoreConcn*this.concnB[ii]/(1.0D + this.assocConsts[ii]*this.concnB[ii]); + } + else{ + System.out.println("Class: DonnanMinim\nMethod: ionConcns"); + System.out.println("error2: no physically meaningfull root"); + System.out.println("root1 = " + root1 + " root2 = " + root2 + " limit = " + limit); + System.exit(0); + } + } + else{ + System.out.println("Class: DonnanMinim\nMethod: ionConcns"); + System.out.println("error3: no physically meaningfull root"); + System.out.println("root1 = " + root1 + " root2 = " + root2 + " limit = " + limit); + System.exit(0); + } + } + } + } + } + + // Method to obtain ionic and complex concentrations for a given Donnan potential + // when more than one ion competes for the ionophore + // by miminimising the sum of the squares of the equations describing each equilibrium + public void calcConcnsMultiK(double potential){ + + + // calculate initial estimates of ionic concentration + double[] start = new double[this.numOfIons]; + double[] step = new double[this.numOfIons]; + + + for(int ii=0; ii<this.numOfIons; ii++){ + if(this.molesT[ii]==0.0D){ + // ion ii not present + this.concnB[ii] = 0.0D; + this.concnA[ii] = 0.0D; + this.complex[ii] = 0.0D; + this.excessConcnA[ii] = 0.0D; + this.excessConcnB[ii] = 0.0D; + this.excessComplex[ii] = 0.0D; + } + else{ + // ion ii present + this.concnB[ii] = this.molesT[ii]/(this.volumeA*this.partCoeffPot[ii] + this.volumeB); + this.concnA[ii] = this.concnB[ii]*this.partCoeffPot[ii]; + this.complex[ii] = 0.0D; + this.excessConcnA[ii] = 0.0D; + this.excessConcnB[ii] = 0.0D; + this.excessComplex[ii] = 0.0D; + } + start[ii] = concnB[ii]; + step[ii] = 0.05*start[ii]; + } + + // obtain ionic and complex concentrations for a given Donnan potential + // by miminimising the sum of the squares of the equations describing each equilibrium + + //Create instance of Minimisation + Minimisation minConcn = new Minimisation(); + + // Create instace of class holding function to be minimised + DonnanConcn functC = new DonnanConcn(); + + // Initialise function functC variable + functC.numOfIons = this.numOfIons; + functC.concnA = this.concnA; + functC.concnB = this.concnB; + functC.molesT = this.molesT; + functC.complex = this.complex; + functC.excessConcnA = this.excessConcnA; + functC.excessConcnB = this.excessConcnB; + functC.excessComplex = this.excessComplex; + functC.assocConsts = this.assocConsts; + functC.indexK = this.indexK; + functC.nonZeroAssocK = this.nonZeroAssocK; + functC.radii = this.radii; + functC.charges = this.charges; + functC.ionophoreConcn = this.ionophoreConcn; + functC.ionophoreRad = this.ionophoreRad; + functC.volumeA = this.volumeA; + functC.volumeB = this.volumeB; + functC.interfacialArea = this.interfacialArea; + functC.epsilonA = this.epsilonA; + functC.epsilonB = this.epsilonB; + functC.epsilonSternA = this.epsilonSternA; + functC.epsilonSternB = this.epsilonSternB; + functC.temp = this.temp; + functC.partCoeffPot = this.partCoeffPot; + functC.sternCap = this.sternCap; + functC.sternDeltaA = this.sternDeltaA; + functC.sternDeltaB = this.sternDeltaB; + functC.chargeValue = this.chargeValue; + functC.chargeSame = this.chargeSame; + functC.interfacialCharge = this.interfacialCharge; + functC.interfacialChargeDensity = this.interfacialChargeDensity; + functC.potential = potential; + functC.includeIc = this.includeIc; + + // Nelder and Mead minimisation procedure + minConcn.nelderMead(functC, start, step, 1e-20, 10000); + + // get values of the Partition B concentrations at minimum + double[] param = minConcn.getParamValues(); + + this.freeIonophoreConcn = this.ionophoreConcn; + for(int i=0; i<this.numOfIons; i++){ + this.concnB[i] = param[i]; + this.concnA[i] = this.concnB[i]*this.partCoeffPot[i]; + this.freeIonophoreConcn -= this.complex[i]; + } + + this.interfacialCharge = functC.interfacialCharge; + this.interfacialChargeDensity = functC.interfacialChargeDensity; + this.sternCap = functC.sternCap; + this.sternDeltaA = functC.sternDeltaA; + this.sternDeltaB = functC.sternDeltaB; + this.sternPotential = functC.sternPotential; + this.diffPotentialA = functC.diffPotentialA; + this.diffPotentialB = functC.diffPotentialB; + } + + + // Print calculated potential and concentrations to a text file + // File title provided by user + public void printToFile(String title){ + + FileOutput fout = new FileOutput(title); + fout.dateAndTimeln(title); + fout.println(); + fout.print("Donnan potential = "); + fout.printsp(Fmath.truncate(this.donnanPotential,7)); + fout.println("volts"); + if(this.includeIc){ + fout.print("Compartment A double layer potential difference = "); + fout.printsp(Fmath.truncate(this.diffPotentialA,7)); + fout.println("volts"); + fout.print("Compartment B double layer potential difference = "); + fout.printsp(Fmath.truncate(this.diffPotentialB,7)); + fout.println("volts"); + fout.print("Stern potential difference = "); + fout.printsp(Fmath.truncate(this.sternPotential,7)); + fout.println("volts"); + } + fout.println(); + + fout.println("Ionic concentrations expressed as mol per cubic decimetre (M)"); + fout.println("Total = equivalent concentration with all ions in compartment A"); + if(this.includeIc){ + fout.printtab("Ion"); + fout.println("Bulk concentrations / M Excess concentrations / M total / M"); + fout.printtab(" "); + fout.println("A B complex A B complex "); + + for(int i=0; i<this.numOfIons; i++){ + fout.printtab(this.ionNames[i]); + fout.printtab(Fmath.truncate(this.concnA[i]*1e-3,7)); + fout.printtab(Fmath.truncate(this.concnB[i]*1e-3,7)); + fout.printtab(Fmath.truncate(this.complex[i]*1e-3,7)); + fout.printtab(Fmath.truncate(this.excessConcnA[i]*1e-3,7)); + fout.printtab(Fmath.truncate(this.excessConcnB[i]*1e-3,7)); + fout.printtab(Fmath.truncate(this.excessComplex[i]*1e-3,7)); + fout.println(Fmath.truncate(this.molesT[i]*1e-3/this.volumeA,7)); + } + } + else{ + fout.printtab("Ion"); + fout.println("A B complex total"); + for(int i=0; i<this.numOfIons; i++){ + fout.printtab(this.ionNames[i]); + fout.printtab(Fmath.truncate(this.concnA[i]*1e-3,7)); + fout.printtab(Fmath.truncate(this.concnB[i]*1e-3,7)); + fout.printtab(Fmath.truncate(this.complex[i]*1e-3,7)); + fout.println(Fmath.truncate(this.molesT[i]*1e-3/this.volumeA,7)); + } + } + + + fout.println(); + fout.println("mols of each ionic species"); + if(this.includeIc){ + fout.printtab("Ion"); + fout.println("Bulk mols Excess mols total mols"); + fout.printtab(" "); + fout.println("A B complex A B complex "); + for(int i=0; i<this.numOfIons; i++){ + fout.printtab(this.ionNames[i]); + fout.printtab(Fmath.truncate(this.concnA[i]*this.volumeA,7)); + fout.printtab(Fmath.truncate(this.concnB[i]*this.volumeB,7)); + fout.printtab(Fmath.truncate(this.complex[i]*this.volumeB,7)); + fout.printtab(Fmath.truncate(this.excessConcnA[i]*this.volumeA,7)); + fout.printtab(Fmath.truncate(this.excessConcnB[i]*this.volumeB,7)); + fout.printtab(Fmath.truncate(this.excessComplex[i]*this.volumeB,7)); + fout.println(Fmath.truncate(this.molesT[i],7)); + } + } + else{ + fout.printtab("Ion"); + fout.println("A B complex total mols"); + for(int i=0; i<this.numOfIons; i++){ + fout.printtab(this.ionNames[i]); + fout.printtab(Fmath.truncate(this.concnA[i]*this.volumeA,7)); + fout.printtab(Fmath.truncate(this.concnB[i]*this.volumeB,7)); + fout.printtab(Fmath.truncate(this.complex[i]*this.volumeB,7)); + fout.println(Fmath.truncate(this.molesT[i],7)); + } + } + fout.println(); + + if(this.includeIc){ + fout.println("Ratios of excess concentration over bulk concentration"); + fout.printtab("Ion"); + fout.println("A B complex"); + for(int i=0; i<this.numOfIons; i++){ + fout.printtab(this.ionNames[i]); + fout.printtab(Fmath.truncate(this.ratioA[i],7)); + fout.printtab(Fmath.truncate(this.ratioB[i],7)); + fout.println(Fmath.truncate(this.ratioC[i],7)); + } + fout.println(); + } + + fout.print("Total ionophore concentration = "); + fout.printsp(Fmath.truncate(this.ionophoreConcn*1e-3,7)); + fout.println("M"); + fout.print("Free ionophore concentration = "); + fout.printsp(Fmath.truncate(this.freeIonophoreConcn*1e-3,7)); + fout.println("M"); + fout.print("Total ionophore moles = "); + fout.printsp(Fmath.truncate(this.ionophoreConcn*this.volumeB,7)); + fout.println("mol"); + fout.print("Ionophore radius = "); + fout.printsp(Fmath.truncate(this.ionophoreRad,7)); + fout.println("m"); + fout.println(); + if(this.includeIc){ + fout.print("Interface charge density = "); + fout.printsp(Fmath.truncate(this.interfacialChargeDensity,7)); + fout.println("C per square metre"); + fout.print("Total interface charge = "); + fout.printsp(Fmath.truncate(this.interfacialCharge,7)); + fout.println("C"); + fout.print("Overall interfacial capacitance = "); + fout.printsp(Fmath.truncate(this.donnanCap*this.interfacialArea,7)); + fout.printsp("F "); + fout.print(" -> "); + fout.printsp(Fmath.truncate(this.donnanCap,7)); + fout.println("Farads per square metre"); + fout.print("Diffuse double layer capacitance (Compartment A) = "); + fout.printsp(Fmath.truncate(this.diffCapA*this.interfacialArea,7)); + fout.printsp("F "); + fout.print(" -> "); + fout.printsp(Fmath.truncate(this.diffCapA,7)); + fout.println("Farads per square metre"); + fout.print("Diffuse double layer capacitance (Compartment B) = "); + fout.printsp(Fmath.truncate(this.diffCapB*this.interfacialArea,7)); + fout.printsp("F "); + fout.print(" -> "); + fout.printsp(Fmath.truncate(this.diffCapB,7)); + fout.println("Farads per square metre"); + fout.print("Stern capacitance = "); + fout.printsp(Fmath.truncate(this.sternCap*this.interfacialArea,7)); + fout.printsp("F "); + fout.print(" -> "); + fout.printsp(Fmath.truncate(this.sternCap,7)); + fout.println("Farads per square metre"); + fout.print("Stern thickness (Compartment A) = "); + fout.printsp(Fmath.truncate(this.sternDeltaA,7)); + fout.println("m"); + fout.print("Stern thickness (Compartment B) = "); + fout.printsp(Fmath.truncate(this.sternDeltaB,7)); + fout.println("m"); + fout.print("Debye length (Compartment A) = "); + fout.printsp(Fmath.truncate(this.recipKappaA,7)); + fout.println("m"); + fout.print("Debye length (Compartment B) = "); + fout.printsp(Fmath.truncate(this.recipKappaB,7)); + fout.println("m"); + fout.println("Compartment thicknesses assuming cubes with one side equal to the interfacial area"); + fout.print("Compartment A thickness = "); + fout.printsp(Fmath.truncate(this.volumeA/this.interfacialArea,7)); + fout.println("m"); + fout.print("Compartment B thickness = "); + fout.printsp(Fmath.truncate(this.volumeB/this.interfacialArea,7)); + fout.println("m"); + fout.println(); + } + fout.print("Volume of compartment A = "); + fout.printsp(this.volumeA); + fout.println("cubic metres"); + fout.print("Volume of compartment B = "); + fout.printsp(this.volumeB); + fout.println("cubic metres"); + fout.print("Interfacial area = "); + fout.printsp(this.interfacialArea); + fout.println("square metres"); + fout.print("Relative electrical permittivity of compartment A = "); + fout.println(this.epsilonA); + fout.print("Relative electrical permittivity of compartment B = "); + fout.println(this.epsilonB); + fout.print("Relative electrical permittivity of compartment A Stern layer= "); + fout.println(this.epsilonSternA); + fout.print("Relative electrical permittivity of compartment B Stern layer= "); + fout.println(this.epsilonSternB); + fout.print("Temperature= "); + fout.printsp(this.temp+Fmath.T_ABS); + fout.println("degrees Celsius"); + fout.println(); + + fout.printtab("Ion"); + fout.printtab("Radius "); + fout.printtab("Charge"); + fout.printtab("Partition"); + fout.printtab("Partition"); + fout.printtab("Delta(mu0)"); + fout.println("Ion-Ionophore "); + + fout.printtab(" "); + fout.printtab(" m "); + fout.printtab(" "); + fout.printtab("Coefficient "); + fout.printtab("Coefficient "); + fout.printtab("/ J per mol"); + fout.println("associaion "); + + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab("at "); + fout.printtab("at zero "); + fout.printtab(" "); + fout.println("constant"); + + fout.printtab(" "); + fout.printtab(" "); + fout.printtab(" "); + fout.printtab("equilibrium "); + fout.printtab("potential "); + fout.printtab(" "); + fout.println("mol per cubic dm"); + + for(int i=0; i<this.numOfIons; i++){ + fout.printtab(this.ionNames[i]); + fout.printtab(Fmath.truncate(this.radii[i],4)); + fout.printtab(this.charges[i]); + fout.printtab(Fmath.truncate(this.partCoeffPot[i],4)); + fout.printtab(Fmath.truncate(this.partCoeff[i],4)); + fout.printtab(Fmath.truncate(this.deltaMu0[i],4)); + fout.println(Fmath.truncate(this.assocConsts[i]*1e3,4)); + + } + + fout.close(); + } + + // Print calculated potential and concentrations to a text file + // Default file title + public void printToFile(){ + String title = "DonnanOutputFile.txt"; + printToFile(title); + } +} + + + + + diff --git a/src/main/java/flanagan/physchem/DonnanConcn.java b/src/main/java/flanagan/physchem/DonnanConcn.java new file mode 100755 index 0000000000000000000000000000000000000000..2c155d104d4e136b5a25df323dbfeb6ab55eb9e2 --- /dev/null +++ b/src/main/java/flanagan/physchem/DonnanConcn.java @@ -0,0 +1,496 @@ +/* +* Classes DonnanConcn +* +* Class DonnanConcn impliments the interface +* MinimisationFunction to the Class Minimisation +* and contains a function that calculates the ionic +* concentrations if the ionophore binds more than +* one species of ion. The sum of the squares of the +* equilibrium functions is minimised. +* +* WRITTEN BY: Michael Thomas Flanagan +* +* DATE: November 2004 +* UPDATE: 6 December 2004 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Donnan.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) November 2004 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.physchem; + +import flanagan.math.*; + +class DonnanConcn implements MinimisationFunction{ + + public int numOfIons = 0; // number of ionic species + public double[] concnA = null; // concentration of ions in partition A (moles per cubic metre) + public double[] concnB = null; // concentration of ions in partition B (moles per cubic metre) + public double[] molesT = null; // total moles of an ion + public double[] complex = null; // concentration of complex in partition B (moles per cubic metre) + public double[] excessConcnA = null; // excess concentration of ions in partition A in interfacial charge (moles per cubic metre) + public double[] excessConcnB = null; // excess concentration of ions in partition B in interfacial charge (moles per cubic metre) + public double[] excessComplex = null; // excess concentration of complex in partition B in interfacial charge (moles per cubic metre) + public double[] assocConsts = null; // association constants of the ions with the ionophore (cubic metres per mole) + public double[] partCoeffPot = null; // partition coefficients in presence of inter-partition, e.g. Donnan, potential + public int[] indexK = null; // ion index of ionic species with non zero assocConsts + public int nonZeroAssocK = 0; // number of ionic species with affinity for the ionophore + public double[] radii = null; // radii of ions + public double[] charges = null; // charge of ions + public double ionophoreConcn = 0.0D; // ionophore concentration - entered as molar, converted to moles per cubic metre + public double ionophoreRad = 0.0D; // ionophore radius (metres) + public double volumeA = 0.0D; // volume of partition A (cubic metres) + public double volumeB = 0.0D; // volume of partition B (cubic metres) + public double interfacialArea = 0.0D; // onterfacial area between Partitions A and B(square metres) + public double epsilonA = 0.0D; // relative electrical permittivity of partition A + public double epsilonB = 0.0D; // relative electrical permittivity of partition B + public double epsilonSternA = 0.0D; // relative electrical permittivity of partition A Stern layer + public double epsilonSternB = 0.0D; // relative electrical permittivity of partition B SternLayer + public double temp = 25.0-Fmath.T_ABS; // Temperature (degrees Kelvin) [Enter temperature in degrees Celsius] + public double diffPotentialA = 0.0D; // Double layer potential difference - compartment A [volts] + public double diffPotentialB = 0.0D; // Double layer potential difference - compartment B [volts] + public double sternPotential = 0.0D; // Stern potential difference [volts] + public double sternCap = 0.0D; // Stern layer capacitance [F] + public double sternDeltaA = 0.0D; // Stern layer thickness in partition A [m] + public double sternDeltaB = 0.0D; // Stern layer thickness in partition B [m] + public double chargeValue = 0; // Absolute value of the charge valency if all are the same, i.e. symmetric electrolytes of the same valency + public boolean chargeSame = true; // = false if chargeValue not the same for all ions + public double interfacialChargeDensity = 0.0D;// interface Charge Density [C per square metre] + public double interfacialCharge = 0.0D; // interface Charge [C] + public boolean includeIc = true; // = true - interface charge included in the calculation of the Donnan potential + // = false - interface charge ignored in the calculation of the Donnan Poptential + public double potential = 0; // current estimate of Donnan potential + private double penalty = 1.0E+50; // penalty function multiplier invoked if an estimated ion concentration is negative + + // method that returns sum of squares of equilibrium equations + // x[0] transfers the current estimate of the concentrations in partition B. + public double function(double[] x){ + + double sumOfSquares = 0.0D; + + // Calculate estimate of complex concentration + if(this.nonZeroAssocK>0 && this.ionophoreConcn>0.0D){ + if(this.nonZeroAssocK==1){ + complex[indexK[0]] = this.assocConsts[indexK[0]]*x[indexK[0]]*this.ionophoreConcn/(1.0D + this.assocConsts[indexK[0]]*x[indexK[0]]); + } + else{ + double[] vec = new double[this.nonZeroAssocK]; + double[][] mat = new double[this.nonZeroAssocK][this.nonZeroAssocK]; + + // set up simultaneous equations + for(int i=0; i<this.nonZeroAssocK; i++){ + vec[i] = this.assocConsts[indexK[i]]*x[indexK[i]]*this.ionophoreConcn; + for(int j=0; j<this.nonZeroAssocK; j++){ + mat[i][j] = this.assocConsts[indexK[i]]*x[indexK[i]]; + if(i==j)mat[i][j] += 1.0D; + } + } + + // solve simultaneous equations to obtain complex concentrations + Matrix matrix = new Matrix(mat); + vec = matrix.solveLinearSet(vec); + for(int i=0; i<this.nonZeroAssocK; i++){ + this.complex[indexK[i]] = vec[i]; + } + } + } + + // Test to check whether interface charge is included in the calculation of the Donnan potential + if(this.includeIc){ + // Calculate the excess charge in the interface region + double excess = Math.abs(this.interfaceCharge(x, this.potential)); + + // Calculate concentrations of ions involved in excess interfacial charge region + excessConcentrations(x, excess, this.potential); + + // Calculate sum of squares of extended equilibrium functions + for(int i=0; i<this.numOfIons; i++){ + double aa = x[i]*(this.volumeB + this.partCoeffPot[i]*this.volumeA) + this.excessConcnA[i]*this.volumeA + (this.excessConcnB[i] + this.complex[i] +this.excessComplex[i])*this.volumeB - this.molesT[i]; + sumOfSquares += aa*aa; + if(x[i]<0.0D)sumOfSquares += x[i]*x[i]*this.penalty; + } + } + else{ + // Calculate sum of squares of equilibrium functions + for(int i=0; i<this.numOfIons; i++){ + double aa = x[i]*(this.volumeB + this.partCoeffPot[i]*this.volumeA) + this.complex[i]*this.volumeB - this.molesT[i]; + sumOfSquares += aa*aa; + if(x[i]<0.0D)sumOfSquares += x[i]*x[i]*this.penalty; + } + } + return sumOfSquares; + } + + + // Calculates the concentrations of ions involved in excess interfacial charge region + public void excessConcentrations(double[] x, double excess, double potential){ + + if(potential==0.0D){ + for(int i=0; i<this.numOfIons; i++){ + this.excessConcnA[i] = 0.0D; + this.excessConcnB[i] = 0.0D; + this.excessComplex[i] = 0.0D; + } + } + else{ + double sumA = 0.0D; + double sumB = 0.0D; + double sumC = 0.0D; + for(int i=0; i<this.numOfIons; i++){ + if(potential>0.0D){ + if(this.charges[i]>0.0D){ + sumB += x[i]*Math.abs(charges[i]); + sumC += this.complex[i]*Math.abs(charges[i]); + + } + else{ + sumA += x[i]*partCoeffPot[i]*Math.abs(charges[i]); + } + } + else{ + if(this.charges[i]<0.0D){ + sumB += x[i]*Math.abs(charges[i]); + sumC += this.complex[i]*Math.abs(charges[i]); + } + else{ + sumA += x[i]*partCoeffPot[i]*Math.abs(charges[i]); + } + } + } + double factorA = excess/(sumA*this.volumeA); + double factorB = excess/((sumB+sumC)*this.volumeB); + for(int i=0; i<this.numOfIons; i++){ + if(potential>0.0D){ + if(this.charges[i]>0.0D){ + this.excessConcnB[i] = Math.abs(this.concnB[i]*factorB); + this.excessComplex[i] = Math.abs(this.complex[i]*factorB); + + } + else{ + this.excessConcnA[i] = Math.abs(this.concnA[i]*factorA); + } + } + else{ + if(this.charges[i]<0.0D){ + this.excessConcnB[i] = Math.abs(this.concnB[i]*factorB); + this.excessComplex[i] = Math.abs(this.complex[i]*factorB); + } + else{ + this.excessConcnA[i] = Math.abs(this.concnA[i]*factorA); + } + } + } + } + } + + + // calculates the excess charge as (surface charge density) in the interfacial region on the Patrition B side + public double interfaceCharge(double[] ions, double potential){ + + if(potential==0){ + this.interfacialCharge=0.0D; + this.interfacialChargeDensity=0.0D; + this.diffPotentialA = 0.0D; + this.diffPotentialB = 0.0D; + this.sternPotential = 0.0D; + } + else{ + // bisection method + double sigmaM = 0.0D; + double funcM = 0.0D; + double sigmaL = 0.0D, funcL = 0.0D; + double sumAions = 0.0D; + double sumBions = 0.0D; + double aveCharge = 0.0D; + for(int i=0; i<this.numOfIons; i++){ + sumBions += Math.abs(ions[i]*this.charges[i]); + sumAions += Math.abs(ions[i]*this.charges[i]*this.partCoeffPot[i]); + aveCharge += Math.abs(charges[i]); + } + aveCharge /= this.numOfIons; + sumBions /= (2.0D*aveCharge); + sumAions /= (2.0D*aveCharge); + double maxQ = 1.2D*Math.sqrt(8.0D*Fmath.N_AVAGADRO*sumBions*Fmath.K_BOLTZMANN*this.temp*Fmath.EPSILON_0*this.epsilonB)*Fmath.sinh(-aveCharge*Fmath.Q_ELECTRON*Math.abs(potential)/(2.0D*Fmath.K_BOLTZMANN*this.temp)); + double sigmaH = maxQ, funcH = 0.0D; + double tolQ = Math.abs(potential)*1e-8; + int nIterQ = 10000; + boolean testQ = true; + int iExpandQ = 0, iBisectQ = 0; + double diffQ = 0.0D; + + while(testQ){ + funcL = icFunct(sigmaL, potential, ions); + funcH = icFunct(sigmaH, potential, ions); + if(funcH*funcL>0.0D){ + iExpandQ++; + if(iExpandQ>10)throw new IllegalArgumentException("iExpandQ has reached its limit"); + diffQ = sigmaH - sigmaL; + sigmaH += diffQ; + } + else{ + testQ=false; + } + } + if(Math.abs(funcL)<=tolQ){ + sigmaM = sigmaL; + } + else{ + if(Math.abs(funcH)<=tolQ){ + sigmaM = sigmaH; + } + else{ + testQ=true; + while(testQ){ + sigmaM = (sigmaL + sigmaH)/2.0D; + funcM = icFunct(sigmaM, potential, ions); + if(Math.abs(funcM)<=tolQ){ + testQ = false; + } + else{ + if(funcL*funcM>0.0D){ + funcL = funcM; + sigmaL = sigmaM; + } + else{ + funcH = funcM; + sigmaH = sigmaM; + } + } + iBisectQ++; + if(iBisectQ>nIterQ){ + System.out.println("Class: DonnanConcn\nMethod: interfaceCharge"); + System.out.println("Maximum iterations in bisection procedure exceeded\nCurrent value of interface charge returned"); + testQ = false; + } + } + } + } + this.interfacialCharge = sigmaM; + this.interfacialChargeDensity = sigmaM/this.interfacialArea; + } + + // return equivalent moles of total excess charge + return this.interfacialCharge/(-Fmath.Q_ELECTRON*Fmath.N_AVAGADRO); + } + + // function for interfaceCharge bisection procedure + // returns the present estimate of the Donnan potential minus the sum of the potential + // differences calculated for the Stern layer and both ionic double layers + public double icFunct(double sigma, double potential, double[] ions){ + double sigmaAbs = Math.abs(sigma); + double sgn = Fmath.sign(potential); + + if(this.chargeSame){ + double NtotalA = 0.0D; + double NtotalB = 0.0D; + for(int i=0; i<this.numOfIons; i++){ + NtotalA += this.concnA[i]; + NtotalB += this.concnB[i] + this.complex[i]; + } + NtotalA /= 2; + NtotalB /= 2; + double preterm = (2.0D*Fmath.K_BOLTZMANN*this.temp)/(-this.chargeValue*Fmath.Q_ELECTRON); + this.diffPotentialA = sgn*preterm*Fmath.asinh(sigmaAbs/Math.sqrt(8.0D*Fmath.N_AVAGADRO*NtotalA*Fmath.K_BOLTZMANN*this.temp*Fmath.EPSILON_0*this.epsilonA)); + this.diffPotentialB = sgn*preterm*Fmath.asinh(sigmaAbs/Math.sqrt(8.0D*Fmath.N_AVAGADRO*NtotalB*Fmath.K_BOLTZMANN*this.temp*Fmath.EPSILON_0*this.epsilonB)); + } + else{ + // bisection method for double layer potentials + // partition A + double phiAm = 0.0D; + double funcM = 0.0D; + double phiAl = 0.0D; + double funcL = 0.0D; + double maxPhiA = 1.1*potential; + double phiAh = maxPhiA; + double funcH = 0.0D; + double tolP = Math.abs(sigma)*1e-1; + int nIterP = 1000; + boolean testP = true; + int iExpandP = 0, iBisectP = 0; + double diffP = 0.0D; + + while(testP){ + funcL = phiAfunct(sigma, phiAl, ions); + funcH = phiAfunct(sigma, phiAh, ions); + if(funcH*funcL>0.0D){ + iExpandP++; + if(iExpandP>10)throw new IllegalArgumentException("iExpandP (partition A) has reached its limit"); + diffP = phiAh - phiAl; + phiAh += diffP; + } + else{ + testP=false; + } + } + + testP=true; + while(testP){ + phiAm = (phiAl + phiAh)/2.0D; + funcM = phiAfunct(sigma, phiAm, ions); + if(Math.abs(funcM)<=tolP){ + this.diffPotentialA = sgn*phiAm; + testP = false; + } + else{ + if(funcL*funcM>0.0D){ + funcL = funcM; + phiAl = phiAm; + } + else{ + funcH = funcM; + phiAh = phiAm; + } + } + iBisectP++; + if(iBisectP>nIterP){ + //System.out.println("Class: DonnanConcn\nMethod: icFunct"); + //System.out.println("Maximum iterations in bisection A procedure exceeded\nCurrent value of interface charge returned"); + System.out.println("phiA = " + phiAm + " sigma = " + sigma + " funcM = " + funcM + " tol = " + tolP); + this.diffPotentialA = sgn*phiAm; + testP = false; + } + } + + // partition B + double phiBm = 0.0D; + double phiBl = 0.0D; + double maxPhiB = -1.1*potential; + double phiBh = maxPhiB; + tolP = Math.abs(potential)*1e-5; + if(tolP==0.0D)tolP=1e-6; + nIterP = 100000; + testP = true; + iExpandP = 0; + iBisectP = 0; + diffP = 0.0D; + + while(testP){ + funcL = phiAfunct(sigma, phiBl, ions); + funcH = phiAfunct(sigma, phiBh, ions); + if(funcH*funcL>0.0D){ + iExpandP++; + if(iExpandP>10)throw new IllegalArgumentException("iExpandP (partition B) has reached its limit"); + diffP = phiBh - phiBl; + phiBh += diffP; + } + else{ + testP=false; + } + } + + if(Math.abs(funcH)<=tolP){ + phiBm = phiBh; + } + else{ + testP=true; + while(testP){ + phiBm = (phiBl + phiBh)/2.0D; + funcM = phiAfunct(sigma, phiBm, ions); + if(Math.abs(funcM)<=tolP){ + testP = false; + } + else{ + if(funcL*funcM>0.0D){ + funcL = funcM; + phiBl = phiBm; + } + else{ + funcH = funcM; + phiBh = phiBm; + } + } + iBisectP++; + if(iBisectP>nIterP){ + System.out.println("Class: DonnanConcn\nMethod: icFunct"); + System.out.println("Maximum iterations in bisection B procedure exceeded\nCurrent value of interface charge returned"); + System.out.println("phiB = " + phiBm + " maxPhiB = " + maxPhiB + " funcM = " + funcM + " tol = " + tolP); + testP = false; + } + } + } + this.diffPotentialB = sgn*phiBm; + } + + // Calculate Stern capacitance + sternCapacitance(ions, sigma, this.diffPotentialA, -this.diffPotentialB); + this.sternPotential = sgn*sigmaAbs/this.sternCap; + + return potential - (this.diffPotentialA + this.diffPotentialB + this.sternPotential); + } + + // Function returns estimated interface charge - interface charge calculated for passed potential + // partition A + public double phiAfunct(double sigma, double potential, double[] ions){ + double sumAsigma = 0.0D; + double sgns = Fmath.sign(sigma); + double preterm1 = 2.0D*Fmath.EPSILON_0*this.epsilonA*Fmath.K_BOLTZMANN*this.temp*Fmath.N_AVAGADRO; + double preterm2 = potential*Fmath.Q_ELECTRON/(Fmath.K_BOLTZMANN*this.temp); + + for(int i=0; i<this.numOfIons; i++){ + + sumAsigma += (preterm1*ions[i]*this.partCoeffPot[i])*(Math.exp(charges[i]*preterm2) - 1.0D); + } + if(sumAsigma<0.0){ + sgns = - sgns; + sumAsigma = -sumAsigma; + } + double diffSigma = sigma - sgns*Math.sqrt(sumAsigma); + return diffSigma; + } + + // Function returns estimated interface charge - interface charge calculated for passed potential + // partition B + public double phiBfunct(double sigma, double potential, double[] ions){ + double sumBsigma = 0.0D; + double sgns = Fmath.sign(sigma); + double preterm1 = 2.0D*Fmath.EPSILON_0*this.epsilonB*Fmath.K_BOLTZMANN*this.temp*Fmath.N_AVAGADRO; + double preterm2 = potential*Fmath.Q_ELECTRON/(Fmath.K_BOLTZMANN*this.temp); + + for(int i=0; i<this.numOfIons; i++){ + sumBsigma += (preterm1*(ions[i]+this.complex[i]))*(Math.exp(charges[i]*preterm2) - 1.0D); + } + if(sumBsigma<0.0){ + sgns = - sgns; + sumBsigma = -sumBsigma; + } + double diffSigma = sigma - sgns*Math.sqrt(sumBsigma); + return diffSigma; + } + + // calculates the Stern capacitances and the Stern potential + // given a surface charge and given diffuse layer potentials + public void sternCapacitance(double[] ions, double sigma, double psiA, double psiB){ + + double denomA = 0.0D; + double denomB = 0.0D; + this.sternDeltaA = 0.0D; + this.sternDeltaB = 0.0D; + double preterm = -Fmath.Q_ELECTRON/(Fmath.K_BOLTZMANN*this.temp); + for(int i=0; i<this.numOfIons; i++){ + this.sternDeltaA += radii[i]*ions[i]*this.partCoeffPot[i]*Math.exp(preterm*psiA*charges[i]); + this.sternDeltaB += (this.radii[i]*ions[i] + this.ionophoreRad*this.complex[i])*Math.exp(-preterm*psiB*charges[i]); + denomA += ions[i]*this.partCoeffPot[i]*Math.exp(preterm*psiA*charges[i]); + denomB += (ions[i] + this.complex[i])*Math.exp(-preterm*psiB*charges[i]); + } + this.sternDeltaA /= denomA; + this.sternDeltaB /= denomB; + this.sternCap = Fmath.EPSILON_0*this.epsilonSternA*this.epsilonSternB/(this.sternDeltaA*this.epsilonSternB + this.sternDeltaB*this.epsilonSternA); + } +} + + diff --git a/src/main/java/flanagan/physchem/DonnanMinim.java b/src/main/java/flanagan/physchem/DonnanMinim.java new file mode 100755 index 0000000000000000000000000000000000000000..dc2cfc5545f5ddd16263b46bd06bd0e0e6870562 --- /dev/null +++ b/src/main/java/flanagan/physchem/DonnanMinim.java @@ -0,0 +1,310 @@ +/* +* Classes DonnanMinim (for Class Donnan) +* +* Class Donnan contains the primary methods for +* calculating a Donnan Potential between two +* partitions of different electrical permittivity +* (dielectric constant) between which any number of +* ionic species may be partitioned and, in one +* partition only, may bind to a neutral ionophore. +* +* Class DonnanMinim impliments the interface +* MinimisationFunction to the Class Minimisation +* and contains a function that calculates the net +* charge in the partition containing the ionophore. +* This net charge is minimised by the minimisation +* function in Minimisation as it should equal to +* zero at equilibrium. +* +* WRITTEN BY: Michael Thomas Flanagan +* +* DATE: November 2004 +* UPDATE: 6 December 2004 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Donnan.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) November 2004 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.physchem; + +import flanagan.math.*; + +class DonnanMinim implements MinimisationFunction{ + + public int numOfIons = 0; // number of ionic species + public double[] concnA = null; // concentration of ions in partition A (moles per cubic metre) + public double[] concnB = null; // concentration of ions in partition B (moles per cubic metre) + public double[] molesT = null; // total moles of an ion + public double[] complex = null; // concentration of complex in partition B (moles per cubic metre) + public double[] excessConcnA = null; // excess concentration of ions in partition A in interfacial charge (moles per cubic metre) + public double[] excessConcnB = null; // excess concentration of ions in partition B in interfacial charge (moles per cubic metre) + public double[] excessComplex = null; // excess concentration of complex in partition B in interfacial charge (moles per cubic metre) + public double[] assocConsts = null; // association constants of the ions with the ionophore (cubic metres per mole) + public int[] indexK = null; // ion index of ionic species with non zero assocConsts + public int nonZeroAssocK = 0; // number of ionic species with affinity for the ionophore + public double[] radii = null; // radii of ions + public double[] charges = null; // charge of ions + public double ionophoreConcn = 0.0D; // ionophore concentration - entered as molar, converted to moles per cubic metre + public double ionophoreRad = 0.0D; // ionophore radius (metres) + public double volumeA = 0.0D; // volume of partition A (cubic metres) + public double volumeB = 0.0D; // volume of partition B (cubic metres) + public double interfacialArea = 0.0D; // onterfacial area between Partitions A and B(square metres) + public double epsilonA = 0.0D; // relative electrical permittivity of partition A + public double epsilonB = 0.0D; // relative electrical permittivity of partition B + public double epsilonSternA = 0.0D; // relative electrical permittivity of partition A Stern layer + public double epsilonSternB = 0.0D; // relative electrical permittivity of partition B SternLayer + public double temp = 25.0-Fmath.T_ABS; // Temperature (degrees Kelvin) [Enter temperature in degrees Celsius] + public double[] partCoeff = null; // partition coefficients in absence of inter-partition, e.g. Donnan, potential + public double[] partCoeffPot = null; // partition coefficients in presence of inter-partition, e.g. Donnan, potential + public double diffPotentialA = 0.0D; // Double layer potential difference - compartment A [volts] + public double diffPotentialB = 0.0D; // Double layer potential difference - compartment B [volts] + public double sternPotential = 0.0D; // Stern potential difference [volts] + public double sternCap = 0.0D; // Stern layer capacitance [F] + public double sternDeltaA = 0.0D; // Stern layer thickness in partition A [m] + public double sternDeltaB = 0.0D; // Stern layer thickness in partition B [m] + public double chargeValue = 0; // Absolute value of the charge valency if all are the same, i.e. symmetric electrolytes of the same valency + public boolean chargeSame = true; // = false if chargeValue not the same for all ions + public double interfacialChargeDensity = 0.0D;// interface Charge Density [C per square metre] + public double interfacialCharge = 0.0D; // interface Charge [C] + public boolean includeIc = true; // = true - interface charge included in the calculation of the Donnan potential + // = false - interface charge ignored in the calculation of the Donnan Poptential + + private double[] start = null; // Minimisation initial estimates + private double[] step = null; // Minimisation step sizes + private double[] param = null; // Minimisation returned values of concnB at minimum + + // Constructor + public DonnanMinim(int noIons){ + this.numOfIons = noIons; + this.start = new double[this.numOfIons]; + this.step = new double[this.numOfIons]; + this.param = new double[this.numOfIons]; + } + + + // method that calculates the net charge in the partition B + // x[0] transfers the current estimate of the Donnan Potential. + public double function(double[] x){ + double chargeBsum = 0.0D; + + // calculate ion and complex concentrations for potential estimate x[0] + this.ionConcns(x[0]); + + for(int i=0; i<this.numOfIons; i++){ + chargeBsum += (this.concnB[i] + this.complex[i])*this.charges[i]; + } + return chargeBsum*chargeBsum; + } + + // Method that calculate partitions A and B and ionophore complex concentrations + // of the iith ion for a given trans partition, e.g. Donnan potential + public void ionConcns(double potential){ + + // calculate partition coefficients for given potential + for(int ii=0; ii<this.numOfIons; ii++){ + this.partCoeffPot[ii] = this.partCoeff[ii]*Math.exp((-potential*this.charges[ii]*Fmath.Q_ELECTRON)/(Fmath.K_BOLTZMANN*this.temp)); + } + + if(!this.includeIc){ + // Interface charge ignored + if(this.nonZeroAssocK<2){ + // Only one or none of the ions with an affinity for the ionophore + calcConcnsSingleK(potential); + } + else{ + // More than one ion competes for the ionophore + + // obtain ionic and complex concentrations for a given Donnan potential + // by miminimising the sum of the squares of the equations describing each equilibrium + calcConcnsMultiK(potential); + } + } + else{ + // interface charge included + + // obtain ionic and complex concentrations for a given Donnan potential + // by miminimising the sum of the squares of the equations describing each equilibrium + calcConcnsMultiK(potential); + } + } + + // Method to calculate ionic concentrations when only one ion or no ions bind to the ionophore + public void calcConcnsSingleK(double potential){ + + for(int ii=0; ii<this.numOfIons; ii++){ + if(this.assocConsts[ii]==0.0D || this.ionophoreConcn==0.0D){ + if(molesT[ii]==0.0D){ + // ion ii not present + this.concnB[ii] = 0.0D; + this.concnA[ii] = 0.0D; + this.complex[ii] = 0.0D; + } + else{ + // No ionophore present or ion ii has no affinity for the ionophore + this.concnB[ii] = this.molesT[ii]/(this.volumeA*this.partCoeffPot[ii] + this.volumeB); + this.concnA[ii] = this.concnB[ii]*this.partCoeffPot[ii]; + this.complex[ii] = 0.0D; + } + } + else{ + // ion ii is the single ionic species with an affinity for the ionophore which is present + // solve quadratic equilibrium equation + // calculate quadratic terms + double aa = this.assocConsts[ii]*(this.volumeB + this.volumeA*this.partCoeffPot[ii]); + double bb = this.volumeB + this.volumeA*this.partCoeffPot[ii] + this.volumeB*this.assocConsts[ii]*ionophoreConcn - this.assocConsts[ii]*this.molesT[ii]; + double cc = -this.molesT[ii]; + // solve quadratic equatiom + double root = bb*bb - 4.0D*aa*cc; + if(root<0.0D){ + System.out.println("Class: DonnanMinim\nMethod: ionConcns\nthe square root term (b2-4ac) of the quadratic = "+root); + System.out.println("this term was set to zero as the negative value MAY have arisen from rounding errors"); + root = 0.0D; + } + double qq = -0.5*(bb + Fmath.sign(bb)*Math.sqrt(root)); + double root1 = qq/aa; + double root2 = cc/qq; + double limit = this.molesT[ii]/(this.volumeA*this.partCoeffPot[ii] + this.volumeB); + if(root1>=0.0D && root1<=limit){ + if(root2<0.0D || root2>limit){ + this.concnB[ii] = root1; + this.concnA[ii] = this.concnB[ii]*this.partCoeffPot[ii]; + this.complex[ii] = this.assocConsts[ii]*this.ionophoreConcn*this.concnB[ii]/(1.0D + this.assocConsts[ii]*this.concnB[ii]); + //this.complex[ii] = (this.molesT[ii] - this.concnA[ii]*this.volumeA - this.concnB[ii]*this.volumeB)/this.volumeB; + } + else{ + System.out.println("Class: DonnanMinim\nMethod: ionConcns"); + System.out.println("error1: no physically meaningfull root"); + System.out.println("root1 = " + root1 + " root2 = " + root2 + " limit = " + limit); + System.exit(0); + } + } + else{ + if(root2>=0.0D && root2<=limit){ + if(root1<0.0D || root1>limit){ + this.concnB[ii] = root2; + this.concnA[ii] = this.concnB[ii]*this.partCoeffPot[ii]; + //this.complex[ii] = (this.molesT[ii] - this.concnA[ii]*this.volumeA - this.concnB[ii]*this.volumeB)/this.volumeB; + this.complex[ii] = this.assocConsts[ii]*this.ionophoreConcn*this.concnB[ii]/(1.0D + this.assocConsts[ii]*this.concnB[ii]); + } + else{ + System.out.println("Class: DonnanMinim\nMethod: ionConcns"); + System.out.println("error2: no physically meaningfull root"); + System.out.println("root1 = " + root1 + " root2 = " + root2 + " limit = " + limit); + System.exit(0); + } + } + else{ + System.out.println("Class: DonnanMinim\nMethod: ionConcns"); + System.out.println("error3: no physically meaningfull root"); + System.out.println("root1 = " + root1 + " root2 = " + root2 + " limit = " + limit); + System.exit(0); + } + } + } + } + } + + // Method to obtain ionic and complex concentrations for a given Donnan potential + // when more than one ion competes for the ionophore + // by miminimising the sum of the squares of the equations describing each equilibrium + public void calcConcnsMultiK(double potential){ + // calculate initial estimates of ionic concentrations + for(int ii=0; ii<this.numOfIons; ii++){ + if(this.molesT[ii]==0.0D){ + // ion ii not present + this.concnB[ii] = 0.0D; + this.concnA[ii] = 0.0D; + this.complex[ii] = 0.0D; + this.excessConcnA[ii] = 0.0D; + this.excessConcnB[ii] = 0.0D; + this.excessComplex[ii] = 0.0D; + } + else{ + // ion ii present + this.concnB[ii] = this.molesT[ii]/(this.volumeA*this.partCoeffPot[ii] + this.volumeB); + this.concnA[ii] = this.concnB[ii]*this.partCoeffPot[ii]; + this.complex[ii] = 0.0D; + this.excessConcnA[ii] = 0.0D; + this.excessConcnB[ii] = 0.0D; + this.excessComplex[ii] = 0.0D; + } + this.start[ii] = concnB[ii]; + this.step[ii] = 0.05*start[ii]; + } + + // obtain ionic and complex concentrations for a given Donnan potential + // by miminimising the sum of the squares of the equations describing each equilibrium + + //Create instance of Minimisation + Minimisation minConcn = new Minimisation(); + + // Create instace of class holding function to be minimised + DonnanConcn functC = new DonnanConcn(); + + // Initialise function functC variable + functC.numOfIons = this.numOfIons; + functC.concnA = this.concnA; + functC.concnB = this.concnB; + functC.molesT = this.molesT; + functC.complex = this.complex; + functC.excessConcnA = this.excessConcnA; + functC.excessConcnB = this.excessConcnB; + functC.excessComplex = this.excessComplex; + functC.assocConsts = this.assocConsts; + functC.indexK = this.indexK; + functC.nonZeroAssocK = this.nonZeroAssocK; + functC.radii = this.radii; + functC.charges = this.charges; + functC.ionophoreConcn = this.ionophoreConcn; + functC.ionophoreRad = this.ionophoreRad; + functC.volumeA = this.volumeA; + functC.volumeB = this.volumeB; + functC.interfacialArea = this.interfacialArea; + functC.epsilonA = this.epsilonA; + functC.epsilonB = this.epsilonB; + functC.epsilonSternA = this.epsilonSternA; + functC.epsilonSternB = this.epsilonSternB; + functC.temp = this.temp; + functC.partCoeffPot = this.partCoeffPot; + functC.sternCap = this.sternCap; + functC.sternDeltaA = this.sternDeltaA; + functC.sternDeltaB = this.sternDeltaB; + functC.chargeValue = this.chargeValue; + functC.chargeSame = this.chargeSame; + functC.interfacialCharge = this.interfacialCharge; + functC.interfacialChargeDensity = this.interfacialChargeDensity; + functC.potential = potential; + functC.includeIc = this.includeIc; + + // Nelder and Mead minimisation procedure + minConcn.nelderMead(functC, this.start, this.step, 1e-20, 10000); + + // get and calculate values of the Partition B concentrations at minimum + param = minConcn.getParamValues(); + + for(int i=0; i<this.numOfIons; i++){ + this.concnB[i] = param[i]; + this.concnA[i] = this.concnB[i]*this.partCoeffPot[i]; + } + + // get values of the interfacial charge + this.interfacialCharge = functC.interfacialCharge; + this.interfacialChargeDensity = functC.interfacialChargeDensity; + + } + } diff --git a/src/main/java/flanagan/physchem/GCSminim.java b/src/main/java/flanagan/physchem/GCSminim.java new file mode 100755 index 0000000000000000000000000000000000000000..94cb3fe1888b1920623ec8c2413460969479e74c --- /dev/null +++ b/src/main/java/flanagan/physchem/GCSminim.java @@ -0,0 +1,73 @@ +/* +* Classes GCSminim (for Class GouyChapmanStern) +* +* +* WRITTEN BY: Michael Thomas Flanagan +* +* DATE: 10 December 2004 +* UPDATE: +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/GouyChapmanStern.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) December 2004 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.physchem; + +import flanagan.math.*; + +class GCSminim implements MinimisationFunction{ + + public double psiDelta = 0.0D; // current value of psi(delta) [diffuseLayerPotential] + public double tempK = 25.0D - Fmath.T_ABS; // temperature [degrees Kelvin] + public double surfaceSiteDensity = 0.0D; // surface adsorption site density + public double surfaceArea= 0.0D; // surface area + public double volume = 0.0D; // electrolyte volume + public int nonZeroAssocK = 0; // number of non-zero association constants + public double[] assocK = null; // surface site association constants + public double[] initConcn = null; // initial ion concentrations + public double[] charges = null; // ion charges + public int[] indexK = null; // indices of the non-zero associaton constants + + // Constructor + public GCSminim(){ + } + + // method that calculates the sum of the squares of g(siteConcn[i]) + // Equations 16a and 16b in the on-line documentation + // x[0] transfers the current estimates of the adsorbed ion concentrations + public double function(double[] x){ + double gFunction = 0.0D; + double arg =0.0D; + int ii = 0; + double convFac = this.surfaceArea/this.volume; + double expTerm = psiDelta*Fmath.Q_ELECTRON/(Fmath.K_BOLTZMANN*this.tempK); + double innerSumTerm =0.0D; + + for(int i=0; i<this.nonZeroAssocK; i++){ + innerSumTerm += x[0]; + } + innerSumTerm = this.surfaceSiteDensity - innerSumTerm; + + for(int i=0; i<this.nonZeroAssocK; i++){ + ii = indexK[i]; + arg = this.assocK[ii]*(this.initConcn[ii] - x[i]*convFac)*Math.exp(expTerm*this.charges[ii])*innerSumTerm - x[0]; + gFunction += arg*arg; + } + return gFunction; + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/physchem/GouyChapmanStern.java b/src/main/java/flanagan/physchem/GouyChapmanStern.java new file mode 100755 index 0000000000000000000000000000000000000000..54bcecbbf41efc49c28a6b857bcb1fc8d27142ee --- /dev/null +++ b/src/main/java/flanagan/physchem/GouyChapmanStern.java @@ -0,0 +1,1892 @@ +/* +* Classes GouyChapmanStern +* +* Class GouyChapmanStern contains the methods for +* calculating a surface potential, surface charge, +* potential profiles and ionic profiles at an +* electrolyte - charged surface interface +* using the Gouy-Chapman or Gouy-Chapman-Stern models. +* +* Class GouyChapmanStern requires Class GCSMinim that +* implements an interface to the required minimisation method +* +* WRITTEN BY: Michael Thomas Flanagan +* +* DATE: 1 December 2004 +* UPDATE: 26 February 2005, 5-7 July 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/GouyChapmanStern.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) December 2004, February 2005 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.physchem; + +import java.util.ArrayList; +import flanagan.physprop.IonicRadii; +import flanagan.io.*; +import flanagan.math.*; +import flanagan.integration.Integration; +import flanagan.integration.IntegralFunction; +import javax.swing.JOptionPane; + +// Class to evaluate the function needed to evaluate the potential at any distance x +// Equation 32a in the documentation, GouyChapmanStern.html +// used in the method, getPotentialAtX(), in the class GouyChapmanStern +class FunctionPatX implements IntegralFunction{ + + public int numOfIons = 0; + public double termOne = 0.0D; + public double expTerm = 0.0D; + public double[] bulkConcn = null; + public double[] charges = null; + + public double function(double x){ + double sigma = 0.0D; + for(int i=0; i<this.numOfIons; i++){ + sigma += (this.bulkConcn[i]*this.termOne)*(Math.exp(-this.expTerm*this.charges[i]*x) - 1.0D); + } + return 1.0D/Math.sqrt(sigma); + } +} + +// GouyChapmanStern Class +public class GouyChapmanStern{ + + private ArrayList<Object> vec = new ArrayList<Object>(); + // vector holding: + // element 0: name of first ion + // element 1: initial concentration of the ion in the electrolyte (moles per cubic metre but entered as moles per cubic decimetre) + // element 2: radius of first ion (metres) + // element 3: charge of first ion + // element 4: association constant of ion with surface sites (cubic metres per mole but entered as cubic decimetres per mole) + // element 5: name of second ion + // etc + private boolean unpackArrayList = false; // = true when the above vector has been unpacked for the calculations + private int numOfIons = 0; // number of ionic species + private int numOfAnions = 0; // number of anionic species + private int numOfCations = 0; // number of cationic species + private String[] ionNames = null; // names of the ions + private double[] initConcnM = null; // initial concentration of ions (Molar) + private double[] initConcn = null; // initial concentration of ions (mol per cubic metre) + private double[] siteConcn = null; // surface concentration of ions adsorbed + private double[] sternConcn = null; // surface concentration of ions in Stern layer but not specifically adsorbed + private double[] bulkConcn = null; // concentration of ions in bulk phase (mol per cubic metre) + private double electrolyteConcn = 0.0D; // electrolyte concentration (average if asymmetric) + private double ionicStrength = 0.0D; // ionic strength of the electrolyte + private int[] indexK = null; // ion index of ionic species with non zero assocConsts + private int nonZeroAssocK = 0; // number of ionic species with affinity for surface sites + private double[] radii = null; // radii of ions + private boolean radiusType = true; // if = true - hydrated radii are taken from Class IonicRadii + // if = false - bare radii are taken from Class IonicRadii + private double[] charges = null; // charge of ions + private double tolNeutral = 1e-6; // fractional tolerance in checking for overall charge neutrality + // when multiplied by total concentration of species of lowest concentration + // gives limit for considering overall neurtality achieved + private double[] assocConstsM = null; // association constants of the ions with surface sites (M^-1) + private double[] assocConsts = null; // association constants of the ions with surface sites (cubic metres per mol) + + private double surfaceSiteDensity = 0.0D; // surface site density - entered as number per square metre + // - converted to moles per square metre + private double freeSurfaceSiteDensity = 0.0D; // surface site density minus all occupied site densities + private boolean surfaceDensitySet = false; // = true if the surface density is enterd + private double epsilon = 0.0D; // relative electrical permittivity of electrolyte + private double epsilonStern = 0.0D; // relative electrical permittivity of the Stern layer + private boolean epsilonSet = false; // = true when epsilon has been set + private double temp = 25.0; // Temperature (degrees Celcius) [Enter temperature in degrees Celsius] + private double tempK = 25.0-Fmath.T_ABS; // Temperature (degrees Kelvin) + private boolean tempSet = false; // = true when temperature has been set + private double surfacePotential = 0.0D; // Surface potential relative to the bulk potential [volts] + private boolean psi0set = false; // = true when surface potential has been entered + private double diffPotential = 0.0D; // diffuse layer potential difference [volts] + private double sternPotential = 0.0D; // Stern potential difference [volts] + private double surfaceArea = 1.0D; // surface area in square metres + private boolean surfaceAreaSet = false; // = true if the surface area is enterd + private double volume = 1.0D; // electrolyte volume in cubic metres + private boolean volumeSet = false; // = true if the volume is enterd + private double sternCap = 0.0D; // Stern layer capacitance [F] + private double diffCap = 0.0D; // diffuse double layer capacitance [F] + private double totalCap = 0.0D; // total surface capacitance [F] + private double sternDelta = 0.0D; // Stern layer thickness [m] + private double chargeValue = 0; // Absolute value of the charge valency if all are the same, i.e. symmetric electrolytes of the same valency + private boolean chargeSame = true; // = false if charge value not the same for all ions + private double averageCharge = 0; // number average absolute charge value of the ions + private double surfaceChargeDensity = 0.0D; // surface charge Density [C per square metre] + private double adsorbedChargeDensity = 0.0D; // adsorbed charge Density [C per square metre] + private double diffuseChargeDensity = 0.0D; // diffuse layer charge Density [C per square metre] + private boolean sigmaSet = false; // = true when surface charge density has been set + private double surfaceCharge = 0.0D; // surface charge [C] + private boolean chargeSet = false; // = true when surface charge set + private double recipKappa = 0.0D; // Debye length + private boolean sternOption = true; // = true: Guoy-Chapman-Stern theory used + // = false: Gouy-Chapman theory used + private double expTerm = 0.0D; // common group of constants: e/kT + private double expTermOver2 = 0.0D; // common group of constants: e/2kT + private double twoTerm = 0.0D; // common group of constants: 2.N.k.T.eps0.eps + private double eightTerm = 0.0D; // common group of constants: 8.N.k.T.eps0.eps + + // Constructor + public GouyChapmanStern(){ + } + + // Method for setting ionic radii taken from Class IonicRadii to hydrated radii + // This is the default option + public void setHydratedRadii(){ + this.radiusType = true; + } + + // Method for setting ionic radii taken from Class IonicRadii to bare radii + public void setBareRadii(){ + this.radiusType = false; + } + + // Method for ignoring the Stern layer + // i.e. using Gouy-Chapman theory NOT Gouy-Chapman-Stern theory + public void ignoreStern(){ + this.sternOption = false; + } + + // Method for reinstating the Stern layer + // i.e. using Gouy-Chapman-Stern theory NOT Gouy-Chapman-theory + public void includeStern(){ + this.sternOption = true; + } + + // Method to add an ionic species + // Concentrations - Molar, assocK - M^-1, radius - metres, charge - valency e.g. +1 + public void setIon(String ion, double concn, double radius, int charge, double assocK){ + this.vec.add(ion); + this.vec.add(new Double(concn)); + this.vec.add(new Double(radius)); + this.vec.add(new Integer(charge)); + this.vec.add(new Double(assocK)); + if(assocK!=0.0D)this.nonZeroAssocK++; + this.numOfIons++; + this.unpackArrayList = false; + } + + // Method to add an ionic species + // Concentrations - Molar, radius - metres, charge - valency e.g. +1 + // association constant = 0.0D + public void setIon(String ion, double concn, double radius, int charge){ + this.vec.add(ion); + this.vec.add(new Double(concn)); + this.vec.add(new Double(radius)); + this.vec.add(new Integer(charge)); + this.vec.add(new Double(0.0D)); + this.numOfIons++; + this.unpackArrayList = false; + } + + // Method to add an ionic species + // default radii and charge taken from class IonicRadii + // if radii not in Ionic Radii, Donnan potential calculated with interface charge neglected + // Concentrations - Molar + public void setIon(String ion, double concn, double assocK){ + IonicRadii ir = new IonicRadii(); + this.vec.add(ion); + this.vec.add(new Double(concn)); + double rad = 0.0D; + if(this.radiusType){ + rad = ir.hydratedRadius(ion); + } + else{ + rad = ir.radius(ion); + } + if(rad==0.0D){ + String mess1 = ion + " radius is not in the IonicRadii list\n"; + String mess2 = "Please enter radius in metres\n"; + rad = Db.readDouble(mess1+mess2); + } + this.vec.add(new Double(rad)); + int charg = 0; + charg = ir.charge(ion); + if(charg==0){ + String mess1 = ion + " charge is not in the IonicRadii list\n"; + String mess2 = "Please enter charge as, e.g +2"; + charg = Db.readInt(mess1+mess2); + } + this.vec.add(new Integer(charg)); + this.vec.add(new Double(assocK)); + if(assocK!=0.0D)this.nonZeroAssocK++; + this.numOfIons++; + this.unpackArrayList = false; + } + + // Method to add an ionic species + // default radii and charge taken from class IonicRadii + // association constant = 0.0D + // Concentrations - Molar + public void setIon(String ion, double concn){ + IonicRadii ir = new IonicRadii(); + this.vec.add(ion); + this.vec.add(new Double(concn)); + double rad = 0.0D; + if(this.radiusType){ + rad = ir.hydratedRadius(ion); + } + else{ + rad = ir.radius(ion); + } + if(rad==0.0D){ + String mess1 = ion + " radius is not in the IonicRadii list\n"; + String mess2 = "Please enter radius in metres\n"; + rad = Db.readDouble(mess1+mess2); + } + this.vec.add(new Double(rad)); + int charg = 0; + charg = ir.charge(ion); + if(charg==0){ + String mess1 = ion + " charge is not in the IonicRadii list\n"; + String mess2 = "Please enter charge as, e.g +2"; + charg = Db.readInt(mess1+mess2); + } + this.vec.add(new Integer(charg)); + this.vec.add(new Double(0.0D)); + this.numOfIons++; + this.unpackArrayList = false; + } + + + // Method to set the surface adsorption site density, moles per square metre + public void setSurfaceSiteDensity(double density){ + this.surfaceSiteDensity = density/Fmath.N_AVAGADRO; + this.surfaceDensitySet = true; + } + + // Method to set the surface area + public void setSurfaceArea(double area){ + this.surfaceArea = area; + this.surfaceAreaSet = true; + } + + // Method to set the electrolyte volume + public void setVolume(double vol){ + this.volume = vol; + this.volumeSet = true; + } + + // Method to set relative permittivities + public void setRelPerm(double epsilon, double epsilonStern){ + this.epsilon = epsilon; + this.epsilonStern = epsilonStern; + this.epsilonSet = true; + } + + // Method to set relative permittivity + // No Stern layer permittivities included + public void setRelPerm(double epsilon){ + this.epsilon = epsilon; + this.epsilonSet = true; + } + + // Method to set temperature (enter as degrees Celsius) + public void setTemp(double temp){ + this.tempK = temp - Fmath.T_ABS; + this.tempSet = true; + } + + // Method to set Surface Charge Density (C per square metre) + public void setSurfaceChargeDensity(double sigma){ + if(this.psi0set){ + System.out.println("You have already entered a surface potential"); + System.out.println("This class allows the calculation of a surface charge density for a given surface potential"); + System.out.println("or the calculation of a surface potential for a given surface charge density"); + System.out.println("The previously entered surface potential will now be ignored"); + this.psi0set = false; + } + + this.surfaceChargeDensity = sigma; + this.sigmaSet = true; + if(this.surfaceAreaSet){ + this.surfaceCharge = sigma*this.surfaceArea; + this.chargeSet = true; + } + } + + // Method to set Surface Charge(C) and surface area + public void setSurfaceCharge(double charge, double area){ + if(this.psi0set){ + System.out.println("You have already entered a surface potential"); + System.out.println("This class allows the calculation of a surface charge density for a given surface potential"); + System.out.println("or the calculation of a surface potential for a given surface charge density"); + System.out.println("The previously entered surface potential will now be ignored"); + this.psi0set = false; + } + + this.surfaceCharge = charge; + this.chargeSet = true; + this.surfaceArea = area; + this.surfaceAreaSet = true; + this.surfaceChargeDensity = charge/this.surfaceArea; + this.sigmaSet = true; + } + + // Method to set Surface Charge(C) + public void setSurfaceCharge(double charge){ + if(this.psi0set){ + System.out.println("You have already entered a surface potential"); + System.out.println("This class allows the calculation of a surface charge density for a given surface potential"); + System.out.println("or the calculation of a surface potential for a given surface charge density"); + System.out.println("The previously entered surface potential will now be ignored"); + this.psi0set = false; + } + + this.surfaceCharge = charge; + this.chargeSet = true; + if(this.surfaceAreaSet){ + this.surfaceChargeDensity = charge/this.surfaceArea; + this.sigmaSet = true; + } + } + + // Method to set Surface Potential (Volts) + public void setSurfacePotential(double psi0){ + if(this.sigmaSet){ + System.out.println("You have already entered a surface charge density"); + System.out.println("This class allows the calculation of a surface potential for a given surface charge density"); + System.out.println("or the calculation of a surface charge density for a given surface potential"); + System.out.println("The previously entered surface charge density will now be ignored"); + this.sigmaSet = false; + } + + this.surfacePotential = psi0; + this.psi0set = true; + } + + // Method to get the diffuse double layer potential [volts] + public double getDiffuseLayerPotential(){ + if(!this.sternOption){ + System.out.println("Class: GouyChapmanStern\nMethod: getDiffuseLayerPotential\nThe Stern modification was not included"); + System.out.println("The value of the diffuse layer potential has been set equal to the surface potential"); + return getSurfacePotential(); + } + + if(this.psi0set && this.sigmaSet){ + return this.diffPotential; + } + else{ + if(this.sigmaSet){ + this.getSurfacePotential(); + return this.diffPotential; + } + else{ + if(this.psi0set){ + this.getSurfaceChargeDensity(); + return this.diffPotential; + } + else{ + System.out.println("Class: GouyChapmanStern\nMethod: getDiffuseLayerPotential\nThe value of the diffuse layer potential has not been calculated\nzero returned"); + System.out.println("Neither a surface potential nor a surface charge density have been entered"); + return 0.0D; + } + } + } + } + + // Method to get the Stern layer potential [volts] + public double getSternLayerPotential(){ + if(!this.sternOption){ + System.out.println("Class: GouyChapmanStern\nMethod: getSternLayerPotential\nThe Stern modification has not been included"); + System.out.println("The value of zero has been returned"); + return 0.0D; + } + + if(this.psi0set && this.sigmaSet){ + return this.sternPotential; + } + else{ + if(this.sigmaSet){ + this.getSurfacePotential(); + return this.sternPotential; + } + else{ + if(this.psi0set){ + this.getSurfaceChargeDensity(); + return this.sternPotential; + } + else{ + System.out.println("Class: GouyChapmanStern\nMethod: getSternLayerPotential\nThe value of the Stern layer potential has not been calculated\nzero returned"); + System.out.println("Neither a surface potential nor a surface charge density have been entered"); + return 0.0D; + } + } + } + } + + // Method to get the Stern Capacitance per square metre + public double getSternCapPerSquareMetre(){ + if(!this.sternOption){ + System.out.println("Class: GouyChapmanStern\nMethod: getSternCapacitance\nThe Stern modification has not been included"); + System.out.println("A value of infinity has been returned"); + return Double.POSITIVE_INFINITY; + } + + if(this.psi0set && this.sigmaSet){ + return this.sternCap; + } + else{ + if(this.sigmaSet){ + this.getSurfacePotential(); + return this.sternCap; + } + else{ + if(this.psi0set){ + this.getSurfaceChargeDensity(); + return this.sternCap; + } + else{ + System.out.println("Class: GouyChapmanStern\nMethod: getSternCap\nThe value of the Stern capacitance has not been calculated\ninfinity returned"); + System.out.println("Neither a surface potential nor a surface charge density have been entered"); + return Double.POSITIVE_INFINITY; + } + } + } + } + + // Method to get the Stern Capacitance + public double getSternCapacitance(){ + if(!this.sternOption){ + System.out.println("Class: GouyChapmanStern\nMethod: getSternCapacitance\nThe Stern modification has not been included"); + System.out.println("A value of infinity has been returned"); + return Double.POSITIVE_INFINITY; + } + + if(!this.surfaceAreaSet){ + System.out.println("Class: GouyChapmanStern\nMethod: getSternCapacitance\nThe surface area has not bee included"); + System.out.println("A value per square metre has been returned"); + return this.sternCap; + } + + if(this.psi0set && this.sigmaSet){ + return this.sternCap*this.surfaceArea; + } + else{ + if(this.sigmaSet){ + this.getSurfacePotential(); + return this.sternCap*this.surfaceArea; + } + else{ + if(this.psi0set){ + this.getSurfaceChargeDensity(); + return this.sternCap*this.surfaceArea; + } + else{ + System.out.println("Class: GouyChapmanStern\nMethod: getSternCapacitance\nThe value of the Stern capacitance has not been calculated\ninfinity returned"); + System.out.println("Neither a surface potential nor a surface charge density have been entered"); + return Double.POSITIVE_INFINITY; + } + } + } + } + + // Method to get the diffuse layer Capacitance per square metre + public double getDiffuseLayerCapPerSquareMetre(){ + if(this.psi0set && this.sigmaSet){ + return this.diffCap; + } + else{ + if(this.sigmaSet){ + this.getSurfacePotential(); + return this.diffCap; + } + else{ + if(this.psi0set){ + this.getSurfaceChargeDensity(); + return this.diffCap; + } + else{ + System.out.println("Class: GouyChapmanStern\nMethod: getDiffuseLayerCapPerSquareMetre\nThe value of the diffuse layer capacitance has not been calculated\ninfinity returned"); + System.out.println("Neither a surface potential nor a surface charge density have been entered"); + return Double.POSITIVE_INFINITY; + } + } + } + } + + // Method to get the diffuse layer Capacitance + public double getDiffuseLayerCapacitance(){ + if(!this.surfaceAreaSet){ + System.out.println("Class: GouyChapmanStern\nMethod: getDiffuseLayerCapacitance\nThe surface area has not bee included"); + System.out.println("A value per square metre has been returned"); + return this.diffCap; + } + + if(this.psi0set && this.sigmaSet){ + return this.diffCap*this.surfaceArea; + } + else{ + if(this.sigmaSet){ + this.getSurfacePotential(); + return this.diffCap*this.surfaceArea; + } + else{ + if(this.psi0set){ + this.getSurfaceChargeDensity(); + return this.diffCap*this.surfaceArea; + } + else{ + System.out.println("Class: GouyChapmanStern\nMethod: getDiffuseLayerCap\nThe value of the diffuse layer capacitance has not been calculated\ninfinity returned"); + System.out.println("Neither a surface potential nor a surface charge density have been entered"); + return Double.POSITIVE_INFINITY; + } + } + } + } + + // Method to get the total capacitance per square metre + public double getTotalCapPerSquareMetre(){ + if(this.psi0set && this.sigmaSet){ + return this.totalCap; + } + else{ + if(this.sigmaSet){ + this.getSurfacePotential(); + return this.totalCap; + } + else{ + if(this.psi0set){ + this.getSurfaceChargeDensity(); + return this.totalCap; + } + else{ + System.out.println("Class: GouyChapmanStern\nMethod: getTotalCapPerSquareMetre\nThe value of the total capacitance has not been calculated\ninfinity returned"); + System.out.println("Neither a surface potential nor a surface charge density have been entered"); + return Double.POSITIVE_INFINITY; + } + } + } + } + + // Method to get the total capacitance + public double getTotalCapacitance(){ + if(!this.surfaceAreaSet){ + System.out.println("Class: GouyChapmanStern\nMethod: getTotalCapacitance\nThe surface area has not bee included"); + System.out.println("A value per square metre has been returned"); + return this.diffCap; + } + + if(this.psi0set && this.sigmaSet){ + return this.totalCap*this.surfaceArea; + } + else{ + if(this.sigmaSet){ + this.getSurfacePotential(); + return this.totalCap*this.surfaceArea; + } + else{ + if(this.psi0set){ + this.getSurfaceChargeDensity(); + return this.totalCap*this.surfaceArea; + } + else{ + System.out.println("Class: GouyChapmanStern\nMethod: getTotalCapacitance\nThe value of the total capacitance has not been calculated\ninfinity returned"); + System.out.println("Neither a surface potential nor a surface charge density have been entered"); + return Double.POSITIVE_INFINITY; + } + } + } + } + + // Method to get the Stern layer thickness + public double getSternThickness(){ + if(!this.sternOption){ + System.out.println("Class: GouyChapmanStern\nMethod: getSternThickness"); + System.out.println("The Stern modification has not been included"); + System.out.println("A value of zero has been returned"); + return 0.0D; + } + + if(this.psi0set && this.sigmaSet){ + return this.sternDelta; + } + else{ + if(this.sigmaSet){ + this.getSurfacePotential(); + return this.sternDelta; + } + else{ + if(this.psi0set){ + this.getSurfaceChargeDensity(); + return this.sternDelta; + } + else{ + System.out.println("Class: GouyChapmanStern\nMethod: getSternThickness\nThe value of the Stern thickness has not been calculated\nzero returned"); + System.out.println("Neither a surface potential nor a surface charge density have been entered"); + return 0.0D; + } + } + } + } + + // Method to get the Debye length + public double getDebyeLength(){ + if(!this.unpackArrayList)unpack(); + return this.calcDebyeLength(); + } + + // Calculate Debye length + private double calcDebyeLength(){ + if(!this.epsilonSet)throw new IllegalArgumentException("The relative permittivitie/s have not been entered"); + if(!this.tempSet)System.out.println("The temperature has not been entered\na value of 25 degrees Celsius has been used"); + + double preterm = 2.0D*Fmath.square(Fmath.Q_ELECTRON)*Fmath.N_AVAGADRO/(Fmath.EPSILON_0*this.epsilon*Fmath.K_BOLTZMANN*this.tempK); + this.recipKappa = 0.0; + for(int i=0; i<this.numOfIons; i++){ + this.recipKappa += this.bulkConcn[i]*charges[i]*charges[i]; + } + this.recipKappa = 1.0D/Math.sqrt(this.recipKappa*preterm); + return this.recipKappa; + } + + // Method to get the ionic strength + public double getIonicStrength(){ + if(!this.unpackArrayList)unpack(); + return this.ionicStrength; + } + + // unpacks the ion storage vector and fills relevant arrays + private void unpack(){ + if(this.numOfIons==0)throw new IllegalArgumentException("No ions have been entered"); + + // change concentrations to moles per cubic metre + // fill primitive data arrays + // calculate total moles + // check if the electrolyte is charge symmetric + this.ionNames = new String[this.numOfIons]; + this.siteConcn = new double[this.numOfIons]; + this.sternConcn = new double[this.numOfIons]; + this.initConcnM = new double[this.numOfIons]; + this.initConcn = new double[this.numOfIons]; + this.bulkConcn = new double[this.numOfIons]; + this.radii = new double[this.numOfIons]; + this.charges = new double[this.numOfIons]; + this.assocConsts = new double[this.numOfIons]; + this.assocConstsM = new double[this.numOfIons]; + this.indexK = new int[this.nonZeroAssocK]; + Double hold = null; + Integer holi = null; + int ii = 0; + this.chargeValue = 0; + this.chargeSame = true; + + for(int i=0; i<numOfIons; i++){ + this.ionNames[i] = (String)this.vec.get(0+i*5); + hold = (Double)this.vec.get(1+i*5); + this.initConcnM[i] = hold.doubleValue(); + this.initConcn[i] = this.initConcnM[i]*1e3; + hold = (Double)this.vec.get(2+i*5); + this.radii[i] = hold.doubleValue(); + holi = (Integer)this.vec.get(3+i*5); + this.charges[i] = holi.intValue(); + hold = (Double)this.vec.get(4+i*5); + this.assocConstsM[i]= hold.doubleValue(); + this.assocConsts[i] = this.assocConstsM[i]*1e-3; + if(this.assocConsts[i]>0.0D){ + indexK[ii] = i; + ii++; + } + + // Check for all ions having same absolute charge + if(i==0){ + this.chargeValue = Math.abs(this.charges[0]); + } + else{ + if(Math.abs(this.charges[i])!=this.chargeValue)this.chargeSame=false; + } + + // calculate number of anionic and cationic species + if(charges[i]<0){ + numOfAnions++; + } + else{ + numOfCations++; + } + if(this.surfaceSiteDensity==0.0D)this.nonZeroAssocK = 0; + } + + // Calculate overall charge, average absolute charge, + // ionic strength and electrolye concentration (only average if asymmetric) + this.averageCharge = 0.0D; + this.ionicStrength = 0.0D; + double overallCharge = 0.0D; + double positives = 0.0D; + double negatives = 0.0D; + for(int i=0; i<numOfIons; i++){ + if(charges[i]>0.0D){ + positives += this.initConcn[i]*charges[i]; + } + else{ + negatives += this.initConcn[i]*charges[i]; + } + overallCharge = positives + negatives; + } + if(Math.abs(overallCharge)>positives*this.tolNeutral){ + String quest0 = "Class: GouyChapmanStern, method: unpack()\n"; + String quest1 = "Total charge = " + overallCharge + " mol/dm, i.e. is not equal to zero\n"; + String quest2 = "Positive charge = " + positives + " mol/dm\n"; + String quest3 = "Do you wish to continue?"; + String quest = quest0 + quest1 + quest2 + quest3; + int res = JOptionPane.showConfirmDialog(null, quest, "Neutrality check", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if(res==1)System.exit(0); + } + + double numer = 0.0D; + double denom = 0.0D; + double anionConc = 0.0D; + double cationConc = 0.0D; + for(int i=0; i<numOfIons; i++){ + this.ionicStrength += initConcn[i]*charges[i]*charges[i]; + if(charges[i]>0){ + cationConc += initConcn[i]; + } + else{ + anionConc += initConcn[i]; + } + if(initConcn[i]>0.0D){ + numer += initConcn[i]*Math.abs(charges[i]); + denom += initConcn[i]; + } + } + this.ionicStrength = this.ionicStrength*1e-3/2.0D; + this.averageCharge = numer/denom; + this.electrolyteConcn = (anionConc + cationConc)/2.0D; + + // initialise site and Stern concentrations + for(int i=0; i<this.numOfIons; i++){ + bulkConcn[i] = initConcn[i]; + siteConcn[i] = 0.0D; + sternConcn[i] = 0.0D; + } + + // calculate commonly used combinations of constants + this.expTerm = -Fmath.Q_ELECTRON/(Fmath.K_BOLTZMANN*this.tempK); // |e|/kT + this.expTermOver2 = this.expTerm/2.0D; // |e|/2kT + this.twoTerm = 2.0D*(Fmath.N_AVAGADRO*Fmath.K_BOLTZMANN)*Fmath.EPSILON_0*this.epsilon*this.tempK; // 2.N.k.T.eps0.eps + this.eightTerm = 4.0D*this.twoTerm; // 8.N.k.T.eps0.eps + + this.unpackArrayList = true; + } + + // Calculate the surface charge density for the set surface potential + public double getSurfaceChargeDensity(){ + if(this.sigmaSet && this.psi0set){ + return this.surfaceChargeDensity; + } + else{ + if(!this.psi0set)throw new IllegalArgumentException("No surface potential has been entered"); + return getSurfaceChargeDensity(this.surfacePotential); + } + } + + // Get the surface charge density for a given surface potential, psi + public double getSurfaceChargeDensity(double psi){ + this.surfaceChargeDensity = this.calcSurfaceChargeDensity(psi); + this.sigmaSet = true; + if(this.surfaceAreaSet){ + this.surfaceCharge = this.surfaceChargeDensity*this.surfaceArea; + this.chargeSet = true; + } + return this.surfaceChargeDensity; + } + + // Calculate the surface charge density for a given surface potential, psi + private double calcSurfaceChargeDensity(double psi){ + double surCharDen = 0.0D; // temporary values of surface charge density + if(!this.epsilonSet)throw new IllegalArgumentException("The relative permittivitie/s have not been entered"); + if(!this.tempSet)System.out.println("The temperature has not been entered\na value of 25 degrees Celsius has been used"); + + if(!this.unpackArrayList)unpack(); + if(this.sternOption){ + if(!this.surfaceAreaSet)throw new IllegalArgumentException("The surface area has not been entered"); + if(!this.volumeSet)throw new IllegalArgumentException("The electrolyte volume has not been entered"); + + // Gouy-Chapman-Stern + if(this.nonZeroAssocK==0){ + // No specific adsorption + if(this.chargeSame){ + // symmetric electrolyte + surCharDen = surfaceChargeDensity0(psi); + } + else{ + // asymmetric electrolyte + surCharDen = surfaceChargeDensity1(psi); + } + } + else{ + // Specific Adsorption + if(this.chargeSame){ + // symmetric electrolyte + surCharDen = surfaceChargeDensity2(psi); + } + else{ + // asymmetric electrolyte + surCharDen = surfaceChargeDensity3(psi); + } + } + } + else{ + // Gouy-Chapman + if(this.chargeSame){ + // symmetric electrolyte + surCharDen = Math.sqrt(this.eightTerm*this.electrolyteConcn)*Fmath.sinh(this.chargeValue*this.expTermOver2*psi); + } + else{ + // asymmetric electrolyte + double sigmaSum = 0.0D; + for(int i=0; i<this.numOfIons; i++){ + sigmaSum += bulkConcn[i]*(Math.exp(-this.expTerm*psi*charges[i])-1.0D); + } + surCharDen = Fmath.sign(psi)*Math.sqrt(this.twoTerm*sigmaSum); + } + } + + this.totalCap = surCharDen/psi; + if(!this.sternOption){ + this.diffPotential = psi; + this.sternCap = Double.POSITIVE_INFINITY; + this.sternPotential = 0.0D; + this.diffCap = this.totalCap; + } + else{ + this.diffPotential = psi - surCharDen/this.sternCap; + this.sternPotential = psi - this.diffPotential; + this.diffCap = (surCharDen + this.adsorbedChargeDensity)/this.diffPotential; + } + return surCharDen; + } + + // Calculate the surface charge for the set surface potential + public double getSurfaceCharge(){ + return getSurfaceCharge(this.surfacePotential); + } + + // Calculate the surface charge for a given surface potential, psi + public double getSurfaceCharge(double psi){ + if(!this.surfaceAreaSet)throw new IllegalArgumentException("No surface area has been entered"); + if(this.sigmaSet){ + this.surfaceCharge = this.surfaceChargeDensity*this.surfaceArea; + } + else{ + if(!this.psi0set)throw new IllegalArgumentException("No surface potential has been entered"); + this.surfaceCharge = this.getSurfaceChargeDensity(psi)*this.surfaceArea; + } + + return this.surfaceCharge; + } + + // Calculate surface charge density for a symmetric electrolyte + // Stern modification without specific adsorption + private double surfaceChargeDensity0(double psi){ + double surCharDen = 0.0D; // temporary values of surface charge density + + // bisection method + double ionSum = 0.0D; + for(int i=0; i<this.numOfIons; i++){ + if(this.charges[i]>0.0){ + ionSum += bulkConcn[i]; + } + } + double sigmaLow = 0.0D; + double sFuncLow = this.sigmaFunction0(sigmaLow, psi); + double sigmaHigh = Math.sqrt(this.eightTerm*ionSum)*Fmath.sinh(this.chargeValue*this.expTermOver2*psi); + double sFuncHigh = this.sigmaFunction0(sigmaHigh, psi); + if(sFuncHigh*sFuncLow>0.0D)throw new IllegalArgumentException("root not bounded"); + double check = Math.abs(sigmaHigh)*1e-6; + boolean test = true; + double sigmaMid = 0.0D; + double sFuncMid = 0.0D; + int nIter = 0; + while(test){ + sigmaMid = (sigmaLow + sigmaHigh)/2.0D; + sFuncMid = this.sigmaFunction0(sigmaMid, psi); + if(Math.abs(sFuncMid)<=check){ + surCharDen = sigmaMid; + test = false; + } + else{ + nIter++; + if(nIter>10000){ + System.out.println("Class: GouyChapmanStern\nMethod: surfaceChargeDensity0\nnumber of iterations exceeded in bisection\ncurrent value of sigma returned"); + surCharDen = sigmaMid; + test = false; + } + else{ + if(sFuncMid*sFuncLow>0){ + sigmaLow=sigmaMid; + sFuncLow=sFuncMid; + } + else{ + sigmaHigh=sigmaMid; + sFuncHigh=sFuncMid; + } + } + + } + } + return surCharDen; + } + + // function to calculate sigma for surfaceChargeDensity0() + private double sigmaFunction0(double sigma, double psi){ + + // calculate psi(delta) Stern capacitance for current estimate of sigma + this.calcSurfacePotential(sigma); + return this.diffPotential - psi + sigma/this.sternCap; + } + + + // Calculate surface charge density for a asymmetric electrolyte + // Stern modification without specific adsorption + private double surfaceChargeDensity1(double psi){ + double surCharDen = 0.0D; // temporary values of surface charge density + + // bisection method + double sigmaLow = 0.0D; + double sFuncLow = this.sigmaFunction0(sigmaLow, psi); + double sigmaHigh = 0.0D; + for(int i=0; i<this.numOfIons; i++){ + sigmaHigh += bulkConcn[i]*this.twoTerm*(Math.exp(-this.expTerm*charges[i]*psi) - 1.0D); + } + sigmaHigh = Fmath.sign(psi)*Math.sqrt(this.twoTerm*sigmaHigh); + double sFuncHigh = this.sigmaFunction0(sigmaHigh, psi); + if(sFuncHigh*sFuncLow>0.0D)throw new IllegalArgumentException("root not bounded"); + double check = Math.abs(sigmaHigh)*1e-6; + boolean test = true; + double sigmaMid = 0.0D; + double sFuncMid = 0.0D; + int nIter = 0; + while(test){ + sigmaMid = (sigmaLow + sigmaHigh)/2.0D; + sFuncMid = this.sigmaFunction0(sigmaMid, psi); + if(Math.abs(sFuncMid)<=check){ + surCharDen = sigmaMid; + test = false; + } + else{ + nIter++; + if(nIter>10000){ + System.out.println("Class: GouyChapmanStern\nMethod: surfaceChargeDensity1\nnumber of iterations exceeded in outer bisection\ncurrent value of sigma returned"); + surCharDen = sigmaMid; + test = false; + } + else{ + if(sFuncLow*sFuncMid>0.0D){ + sigmaLow = sigmaMid; + sFuncLow = sFuncMid; + } + else{ + sigmaHigh = sigmaMid; + sFuncHigh = sFuncMid; + } + } + } + } + return surCharDen; + } + + // Calculate the Stern thickness, adsorbed ion concentrations and Stern layer non-adsorbed ion concentrations + // for a given potential, psi + private double calcDelta(double psi){ + double numer = 0.0D; + double denom = 0.0D; + double delta = 0.0; + + for(int i=0; i<this.numOfIons; i++){ + this.sternConcn[i] = this.bulkConcn[i]*Math.exp(-this.charges[i]*this.expTerm); + + numer += this.sternConcn[i]*this.radii[i]; + denom += this.sternConcn[i]; + } + + this.sternDelta = numer/denom; + + return this.sternDelta; + } + + // Calculate surface charge density for a symmetric electrolyte + // Stern modification with specific adsorption + private double surfaceChargeDensity2(double psi){ + double surCharDen = 0.0D; // temporary values of surface charge density + + // bisection method + double sigmaAdsPos = 0.0D; + double sigmaAdsNeg = 0.0D; + for(int i=0; i<this.nonZeroAssocK; i++){ + if(this.charges[indexK[i]]>0){ + sigmaAdsPos=surfaceSiteDensity; + } + else{ + sigmaAdsNeg=-surfaceSiteDensity; + } + } + + double sigmaLow = 0.0D; + double sigmaHigh = 0.0D; + double ionSum = 0.0D; + for(int i=0; i<this.numOfIons; i++){ + ionSum += bulkConcn[i]; + } + ionSum /=2.0D; + sigmaHigh = Math.sqrt(ionSum*this.eightTerm)*Fmath.sinh(this.expTermOver2*psi*this.chargeValue); + if(sigmaHigh>0.0D){ + sigmaHigh += sigmaAdsPos; + sigmaLow -= sigmaAdsNeg; + } + else{ + sigmaHigh -= sigmaAdsNeg; + sigmaLow += sigmaAdsPos; + } + System.out.println("pp0 "+ sigmaLow + " " + psi + " "+ionSum + " " +ionSum*this.eightTerm); + double sFuncLow = this.sigmaFunction2(sigmaLow, psi); + System.out.println("pp1 "+ sigmaHigh + " " + psi + " "+ionSum + " " +this.chargeValue+" "+Math.sqrt(ionSum*this.eightTerm) + " " + this.expTermOver2*psi*this.chargeValue + " " + Fmath.sinh(this.expTermOver2*psi*this.chargeValue)); + double sFuncHigh = this.sigmaFunction2(sigmaHigh, psi); + if(sFuncHigh*sFuncLow>0.0D)throw new IllegalArgumentException("root not bounded"); + double check = Math.abs(sigmaHigh)*1e-6; + boolean test = true; + double sigmaMid = 0.0D; + double sFuncMid = 0.0D; + int nIter = 0; + while(test){ + sigmaMid = (sigmaLow + sigmaHigh)/2.0D; + sFuncMid = this.sigmaFunction2(sigmaMid, psi); + if(Math.abs(sFuncMid)<=check){ + surCharDen = sigmaMid; + test = false; + } + else{ + nIter++; + if(nIter>10000){ + System.out.println("Class: GouyChapmanStern\nMethod: surfaceChargeDensity2\nnumber of iterations exceeded in outer bisection\ncurrent value of sigma returned"); + surCharDen = sigmaMid; + test = false; + } + else{ + if(sFuncLow*sFuncMid>0.0D){ + sigmaLow = sigmaMid; + sFuncLow = sFuncMid; + } + else{ + sigmaHigh = sigmaMid; + sFuncHigh = sFuncMid; + } + } + + } + } + return surCharDen; + } + + // function to calculate sigma for surfaceChargeDensity2() + private double sigmaFunction2(double sigma, double psi){ + System.out.println("F2begin"); + // bisection method for psi(delta) + double psiLow = -10*psi; + double pFuncLow = this.psiFunctionQ(psiLow, psi, sigma); + double psiHigh = 10*psi; + double pFuncHigh = this.psiFunctionQ(psiHigh, psi, sigma); + System.out.println("qq " + pFuncLow + " "+pFuncHigh+" "+ psiLow+" "+psiHigh); + if(pFuncHigh*pFuncLow>0.0D)throw new IllegalArgumentException("root not bounded"); + double check = Math.abs(psi)*1e-6; + boolean test = true; + double psiMid = 0.0D; + double pFuncMid = 0.0D; + int nIter = 0; + while(test){ + psiMid = (psiLow + psiHigh)/2.0D; + pFuncMid = this.psiFunctionQ(psiMid, psi, sigma); + if(Math.abs(pFuncMid)<=check){ + test = false; + } + else{ + nIter++; + if(nIter>10000){ + System.out.println("Class: GouyChapmanStern\nMethod: surfaceChargeDensity3\nnumber of iterations exceeded in inner bisection\ncurrent value of sigma returned"); + test = false; + } + if(pFuncMid*pFuncHigh>0){ + psiHigh = psiMid; + pFuncHigh = pFuncMid; + } + else{ + psiLow = psiMid; + pFuncLow = pFuncMid; + } + } + } + + double sigmaEst = 0.0D; + for(int i=0; i<this.numOfIons; i++){ + sigmaEst += bulkConcn[i]; + } + sigmaEst = Math.sqrt(this.eightTerm*sigmaEst/2.0D)*Fmath.sinh(this.expTermOver2*psi*this.chargeValue); + System.out.println("F2end"); + + return sigma + this.adsorbedChargeDensity - sigmaEst; + } + + // Calculate surface charge density for a asymmetric electrolyte + // Stern modification with specific adsorption + private double surfaceChargeDensity3(double psi){ + double surCharDen = 0.0D; // temporary values of surface charge density + + // bisection method + double sigmaAdsPos = 0.0D; + double sigmaAdsNeg = 0.0D; + for(int i=0; i<this.nonZeroAssocK; i++){ + if(this.charges[indexK[i]]>0){ + sigmaAdsPos=surfaceSiteDensity; + } + else{ + sigmaAdsNeg=-surfaceSiteDensity; + } + } + + double sigmaLow = 0.0D; + double sigmaHigh = 0.0D; + for(int i=0; i<this.numOfIons; i++){ + sigmaHigh += bulkConcn[i]*this.twoTerm*(Math.exp(-this.expTerm*charges[i]*psi) - 1.0D); + } + sigmaHigh = Fmath.sign(psi)*Math.sqrt(sigmaHigh); + if(sigmaHigh>0.0D){ + sigmaHigh += sigmaAdsPos; + sigmaLow -= sigmaAdsNeg; + } + else{ + sigmaHigh -= sigmaAdsNeg; + sigmaLow += sigmaAdsPos; + } + double sFuncLow = this.sigmaFunction3(sigmaLow, psi); + double sFuncHigh = this.sigmaFunction3(sigmaHigh, psi); + if(sFuncHigh*sFuncLow>0.0D)throw new IllegalArgumentException("root not bounded"); + double check = Math.abs(sigmaHigh)*1e-6; + boolean test = true; + double sigmaMid = 0.0D; + double sFuncMid = 0.0D; + int nIter = 0; + while(test){ + sigmaMid = (sigmaLow + sigmaHigh)/2.0D; + sFuncMid = this.sigmaFunction3(sigmaMid, psi); + if(Math.abs(sFuncMid)<=check){ + surCharDen = sigmaMid; + test = false; + } + else{ + nIter++; + if(nIter>10000){ + System.out.println("Class: GouyChapmanStern\nMethod: surfaceChargeDensity3\nnumber of iterations exceeded in outer bisection\ncurrent value of sigma returned"); + surCharDen = sigmaMid; + test = false; + } + else{ + if(sFuncLow*sFuncMid>0.0D){ + sigmaLow = sigmaMid; + sFuncLow = sFuncMid; + } + else{ + sigmaHigh = sigmaMid; + sFuncHigh = sFuncMid; + } + } + + } + } + return surCharDen; + } + + // function to calculate sigma for surfaceChargeDensity2() + private double sigmaFunction3(double sigma, double psi){ + // bisection method for psi(delta) + double psiLow = 0.0D; + double pFuncLow = this.psiFunctionQ(psiLow, psi, sigma); + double psiHigh = psi; + double pFuncHigh = this.psiFunctionQ(psiHigh, psi, sigma); + if(pFuncHigh*pFuncLow>0.0D)throw new IllegalArgumentException("root not bounded"); + double check = Math.abs(psi)*1e-6; + boolean test = true; + double psiMid = 0.0D; + double pFuncMid = 0.0D; + int nIter = 0; + while(test){ + psiMid = (psiLow + psiHigh)/2.0D; + pFuncMid = this.psiFunctionQ(psiMid, psi, sigma); + if(Math.abs(pFuncMid)<=check){ + test = false; + } + else{ + nIter++; + if(nIter>10000){ + System.out.println("Class: GouyChapmanStern\nMethod: sigmaFunction3\nnumber of iterations exceeded in inner bisection\ncurrent value of sigma returned"); + test = false; + } + if(pFuncMid*pFuncHigh>0){ + psiHigh = psiMid; + pFuncHigh = pFuncMid; + } + else{ + psiLow = psiMid; + pFuncLow = pFuncMid; + } + } + } + + double sigmaEst = 0.0D; + for(int i=0; i<this.numOfIons; i++){ + sigmaEst += bulkConcn[i]*this.twoTerm*(Math.exp(-this.expTerm*charges[i]*psiMid) - 1.0D); + } + sigmaEst = Fmath.sign(psiMid)*Math.sqrt(sigmaEst); + + return sigma + this.adsorbedChargeDensity - sigmaEst; + } + + // Function to calculate psi(delta) when specific adsorption occurs + private double psiFunctionQ(double psiDelta, double psi0, double sigma){ + + this.sternDelta = this.calcDeltaQ(psiDelta); + this.diffPotential = psiDelta; + this.sternCap = this.epsilonStern*Fmath.EPSILON_0/this.sternDelta; + System.out.println("aaa " + psiDelta + " " + psi0 + " " + sigma/this.sternCap + " " + sigma); + return psiDelta - psi0 + sigma/this.sternCap; + } + + // Calculate the Stern thickness, adsorbed ion concentrations and Stern layer non-adsorbed ion concentrations + // for a given potential, psi + // and speicific adsorption occurring + private double calcDeltaQ(double psi){ + double numer = 0.0D; + double denom = 0.0D; + double convFac = this.surfaceArea/this.volume; + int ii = 0; + + // calculate adsorbed ion concentrations + if(this.nonZeroAssocK==1){ + ii = indexK[0]; + double hold = this.assocConsts[ii]*Math.exp(-charges[ii]*psi*this.expTerm); + double aa = hold*convFac; + double bb = -(1.0D + this.initConcn[ii]*hold + this.surfaceSiteDensity*hold*convFac); + double cc = this.initConcn[ii]*this.surfaceSiteDensity*hold; + // solve quadratic equatiom + double root = bb*bb - 4.0D*aa*cc; + if(root<0.0D){ + System.out.println("Class: GouyChapmanStern\nMethod: calcDeltaQ\nthe square root term (b2-4ac) of the quadratic = "+root); + System.out.println("this term was set to zero as the negative value MAY have arisen from rounding errors"); + root = 0.0D; + } + double qq = -0.5*(bb + Fmath.sign(bb)*Math.sqrt(root)); + double root1 = qq/aa; + double root2 = cc/qq; + double limit = this.surfaceSiteDensity*1.001D; + + if(root1>=0.0D && root1<=limit){ + if(root2<0.0D || root2>limit){ + this.siteConcn[indexK[0]] = root1; + this.bulkConcn[indexK[0]] = this.initConcn[indexK[0]] - this.siteConcn[indexK[0]]*this.surfaceArea/this.volume; + } + else{ + System.out.println("Class: GouyChapmanStern\nMethod: ionConcns"); + System.out.println("error1: no physically meaningfull root"); + System.out.println("root1 = " + root1 + " root2 = " + root2 + " limit = " + limit); + System.exit(0); + } + } + else{ + if(root2>=0.0D && root2<=limit){ + if(root1<0.0D || root1>limit){ + this.siteConcn[indexK[0]] = root2; + this.bulkConcn[indexK[0]] = this.initConcn[indexK[0]] - this.siteConcn[indexK[0]]*this.surfaceArea/this.volume; + } + else{ + System.out.println("Class: GouyChapmanStern\nMethod: ionConcns"); + System.out.println("error2: no physically meaningfull root"); + System.out.println("root1 = " + root1 + " root2 = " + root2 + " limit = " + limit); + System.exit(0); + } + } + else{ + System.out.println("Class: GouyChapmanStern\nMethod: ionConcns"); + System.out.println("error3: no physically meaningfull root"); + System.out.println("root1 = " + root1 + " root2 = " + root2 + " limit = " + limit); + System.exit(0); + } + } + } + else{ + // More than one non-zero association constant + // Minimisation procedure + + // Initial estimates + double[] vec = new double[this.nonZeroAssocK]; + double[][] mat = new double[this.nonZeroAssocK][this.nonZeroAssocK]; + + // set up simultaneous equations + double expPsiTerm = -psi*this.expTerm; + for(int i=0; i<this.nonZeroAssocK; i++){ + ii = indexK[i]; + vec[i] = this.assocConsts[ii]*this.initConcn[ii]*this.surfaceSiteDensity*Math.exp(charges[ii]*expPsiTerm); + for(int j=0; j<this.nonZeroAssocK; j++){ + mat[i][j] = this.assocConsts[ii]*this.initConcn[ii]*Math.exp(charges[ii]*expPsiTerm); + if(i==j)mat[i][j] += 1.0D; + } + } + + // solve simultaneous equations to obtain complex concentrations + Matrix matrix = new Matrix(mat); + vec = matrix.solveLinearSet(vec); + for(int i=0; i<this.nonZeroAssocK; i++){ + this.siteConcn[indexK[i]] = vec[i]; + } + } + + // Create an instances of Minimisation and the minimisation function, GCSminim + Minimisation min = new Minimisation(); + GCSminim functA = new GCSminim(); + + // set minimisation function variables + functA.psiDelta = psi; // current value of psi(delta) [diffuseLayerPotential] + functA.tempK = this.tempK; // temperature + functA.surfaceSiteDensity = this.surfaceSiteDensity; // surface adsorption site density + functA.surfaceArea = this.surfaceArea; // surface ares + functA.volume = this.volume; // electrolyte volume + functA.nonZeroAssocK = this.nonZeroAssocK; // number of non-zero association constants + functA.assocK = this.assocConsts; // surface site association constants + functA.initConcn = this.initConcn; // initial ion concentrations + functA.charges = this.charges; // ion charges + functA.indexK = this.indexK; // indices of the non-zero associaton constants + + // set initial estimates, step sizes + double[] start = new double[this.nonZeroAssocK]; + + double[] step = new double[this.nonZeroAssocK]; + for(int i=0; i<this.nonZeroAssocK; i++){ + start[i] = this.surfaceSiteDensity/this.nonZeroAssocK; + step[i] = start[i]*0.05D; + } + + // covergence tolerance and maximum number of iteration allowed + double tolerance = this.surfaceSiteDensity*1e-8; + int maxIter = 100000; + + // Perform minimisation + min.nelderMead(functA, start, step, tolerance, maxIter); + + // Get best estimates of the site concentrations + double[] param = min.getParamValues(); + for(int i=0; i<this.nonZeroAssocK; i++){ + ii = indexK[i]; + this.siteConcn[ii] = param[i]; + this.bulkConcn[ii] = this.initConcn[ii] - param[i]*this.surfaceArea/this.volume; + } + + // Calculte Stern delta and adsorbed charge density + this.adsorbedChargeDensity = 0.0D; + double factor1 = -Fmath.Q_ELECTRON*Fmath.N_AVAGADRO; + double factor2 = this.surfaceArea/this.volume; + for(int i=0; i<this.numOfIons; i++){ + this.sternConcn[i] = this.bulkConcn[i]*Math.exp(-this.charges[i]*this.expTerm); + this.adsorbedChargeDensity += this.siteConcn[i]*charges[i]*factor1; + numer += (this.sternConcn[i] + this.siteConcn[i]*factor2)*this.radii[i]; + denom += this.sternConcn[i] + this.siteConcn[i]*factor2; + } + + double delta = numer/denom; + + return delta; + } + + // Method to get the adsorbed ion charge density [C per square metre] + public double getAdsorbedChargeDensity(){ + if(!this.sternOption || this.nonZeroAssocK==0){ + return 0.0D; + } + + if(this.psi0set && this.sigmaSet){ + return this.adsorbedChargeDensity; + } + else{ + if(this.sigmaSet){ + this.getSurfacePotential(); + return this.sternPotential; + } + else{ + if(this.psi0set){ + this.getSurfaceChargeDensity(); + return this.adsorbedChargeDensity; + } + else{ + System.out.println("Class: GouyChapmanStern\nMethod: getAdsorbedChargeDensity\nThe value of the adsorbed ion charge density has not been calculated\nzero returned"); + System.out.println("Neither a surface potential nor a surface charge density have been entered"); + return 0.0D; + } + } + } + } + + // Method to get the diffuse layer charge density [C per square metre] + public double getDiffuseChargeDensity(){ + double ads = this.getAdsorbedChargeDensity(); + this.diffuseChargeDensity = -(this.surfaceChargeDensity + ads); + return this.diffuseChargeDensity; + } + + // Get the surface potential for a given surface charge density, sigma + public double getSurfacePotential(double sigma){ + this.surfacePotential = calcSurfacePotential(sigma); + this.psi0set = true; + return this.surfacePotential; + } + + // Calculate the surface potential for a given surface charge density, sigma + private double calcSurfacePotential(double sigma){ + double surPot = 0.0D; // temporary values of the surface potential + + if(!this.epsilonSet)throw new IllegalArgumentException("The relative permittivitie/s have not been entered"); + if(!this.tempSet)System.out.println("The temperature has not been entered\na value of 25 degrees Celsius has been used"); + + if(this.psi0set && this.sigmaSet)return this.surfacePotential; + + if(!this.unpackArrayList)unpack(); + + if(this.sternOption){ + // Gouy-Chapman-Stern + if(this.nonZeroAssocK==0){ + // No specific adsorption + if(this.chargeSame){ + // symmetric electrolyte + this.diffPotential = Fmath.asinh(sigma/Math.sqrt(this.eightTerm*this.electrolyteConcn))/(this.chargeValue*this.expTermOver2); + } + else{ + // asymmetric electrolyte + this.diffPotential = surfacePotential1(sigma); + } + this.sternCap = Fmath.EPSILON_0*this.epsilonStern/this.calcDelta(this.diffPotential); + surPot = this.diffPotential + sigma/this.sternCap; + this.totalCap = sigma/this.surfacePotential; + this.diffCap = sigma/this.diffPotential; + } + else{ + // Specific absorption + if(this.chargeSame){ + // symmetric electrolyte + surPot = surfacePotential2(sigma); + } + else{ + // asymmetric electrolyte + surPot = surfacePotential3(sigma); + } + } + + } + else{ + // Gouy-Chapman + if(this.chargeSame){ + // symmetric electrolyte + double preterm = Math.sqrt(this.eightTerm*this.electrolyteConcn); + this.surfacePotential = Fmath.asinh(this.surfaceChargeDensity/preterm)/(this.chargeValue*this.expTermOver2); + } + else{ + // asymmetric electrolyte + surPot = surfacePotential4(sigma); + } + this.diffPotential = surPot; + this.sternPotential = 0.0D; + this.totalCap = sigma/surPot; + this.diffCap = sigma/this.diffPotential; + this.sternCap = Double.POSITIVE_INFINITY; + } + + return surPot; + } + + // Calculate the surface charge for the set surface potential + public double getSurfacePotential(){ + if(!this.sigmaSet)throw new IllegalArgumentException("No surface charge density has been entered"); + return getSurfacePotential(this.surfaceChargeDensity); + } + + // Calculate surface potential for a asymmetric electrolyte + // Stern modification ignored + private double surfacePotential4(double sigma){ + double surPot = 0.0D; // temporary values of the surface potential + + // bisection method + double psiLow = 0.0D; + double pFuncLow = this.psiFunction4(psiLow, sigma); + double asinhDenom = Math.sqrt(this.eightTerm*this.electrolyteConcn); + double psiHigh = (10.0D/(this.averageCharge*this.expTerm))*Fmath.asinh(sigma/asinhDenom); + double pFuncHigh = this.psiFunction4(psiHigh, sigma); + if(pFuncHigh*pFuncLow>0.0D)throw new IllegalArgumentException("root not bounded"); + double check = Math.abs(psiHigh)*1e-6; + boolean test = true; + double psiMid = 0.0D; + double pFuncMid = 0.0D; + int nIter = 0; + while(test){ + psiMid = (psiLow + psiHigh)/2.0D; + pFuncMid = this.psiFunction4(psiMid, sigma); + if(Math.abs(pFuncMid)<=check){ + surPot = psiMid; + test = false; + } + else{ + nIter++; + if(nIter>10000){ + System.out.println("Class: GouyChapmanStern\nMethod: getSurfacePotential\nnumber of iterations exceeded in outer bisection\ncurrent value of sigma returned"); + surPot = psiMid; + test = false; + } + else{ + if(pFuncLow*pFuncMid>0.0D){ + psiLow = psiMid; + pFuncLow = pFuncMid; + } + else{ + psiHigh = psiMid; + pFuncHigh = pFuncMid; + } + } + } + } + return surPot; + } + + // function to calculate surfacePotential function for surfacePotential4() + private double psiFunction4(double psi, double sigma){ + double sigmaEst = 0.0D; + for(int i=0; i<this.numOfIons; i++){ + sigmaEst += bulkConcn[i]*this.twoTerm*(Math.exp(-this.expTerm*charges[i]*psi) - 1.0D); + } + sigmaEst = Fmath.sign(sigma)*Math.sqrt(sigmaEst); + + return sigma - sigmaEst; + } + + // Calculate surface potential for a given charge density for a asymmetric electrolyte + // Stern modification without specific adsorption + private double surfacePotential1(double sigma){ + double difPot = 0.0D; // temporary values of the diffuse potential + + // bisection method + double psiLow = 0.0D; + double pFuncLow = this.psiFunction1(psiLow, sigma); + double psiHigh = (5.0D/(this.expTerm*this.chargeValue))*Fmath.asinh(sigma/Math.sqrt(this.eightTerm*this.electrolyteConcn)); + double pFuncHigh = this.psiFunction1(psiHigh, sigma); + if(pFuncHigh*pFuncLow>0.0D)throw new IllegalArgumentException("root not bounded"); + double check = Math.abs(psiHigh)*1e-6; + boolean test = true; + double psiMid = 0.0D; + double pFuncMid = 0.0D; + int nIter = 0; + while(test){ + psiMid = (psiLow + psiHigh)/2.0D; + pFuncMid = this.psiFunction1(psiMid, sigma); + if(Math.abs(pFuncMid)<=check){ + this.diffPotential = psiMid; + test = false; + } + else{ + nIter++; + if(nIter>10000){ + System.out.println("Class: GouyChapmanStern\nMethod: getSurfacePotential\nnumber of iterations exceeded in outer bisection\ncurrent value of sigma returned"); + this.diffPotential = psiMid; + test = false; + } + else{ + if(pFuncLow*pFuncMid>0.0D){ + psiLow = psiMid; + pFuncLow = pFuncMid; + } + else{ + psiHigh = psiMid; + pFuncHigh = pFuncMid; + } + } + + } + } + return difPot; + } + + // function to calculate diffPotential for surfacePotential1() + private double psiFunction1(double psi, double sigma){ + + double func = 0.0D; + for(int i=0; i<this.numOfIons; i++){ + func += this.twoTerm*bulkConcn[i]*(Math.exp(-charges[i]*psi*this.expTerm) - 1.0D); + } + return sigma - Fmath.sign(sigma)*Math.sqrt(func); + } + + // method to calculate the potential at a distance, x, from the surface + public double getPotentialAtX(double xDistance){ + if(!this.psi0set && !this.sigmaSet)throw new IllegalArgumentException("Neither a surface potential nor a surface charge/density have been entered"); + if(this.sigmaSet && !this.psi0set)this.getSurfacePotential(); + if(this.psi0set && !this.sigmaSet)this.getSurfaceChargeDensity(); + + double potAtX = 0.0D; + + if(xDistance==0.0D){ + // distance, x, is zero metres from charged surface + potAtX = this.surfacePotential; + } + else{ + if(this.sternOption){ + // distance, x, coincides with the Stern interface + if(xDistance==this.sternDelta){ + potAtX = this.diffPotential; + } + else{ + if(xDistance<this.sternDelta){ + // distance, x, is within the Stern layer + potAtX = this.surfacePotential - (xDistance/this.sternDelta)*(this.surfacePotential - this.diffPotential); + } + else{ + // distance, x, is greater than the Stern layer thickness + potAtX = this.calcPotAtX(this.diffPotential, xDistance); + } + } + } + else{ + // no Stern layer and distance, x, is greater than zero + potAtX = this.calcPotAtX(this.surfacePotential, xDistance); + } + } + return potAtX; + } + + // calculates potential at x for getPotentialAtX() + private double calcPotAtX(double psiL, double xDistance){ + double potAtX = 0.0D; + if(this.chargeSame){ + //symmetric elctrolyte + double kappa = Math.sqrt(2.0D*Fmath.square(Fmath.Q_ELECTRON*this.chargeValue)*Fmath.N_AVAGADRO*this.electrolyteConcn/(Fmath.EPSILON_0*this.epsilon*Fmath.K_BOLTZMANN*this.tempK)); + double expPart = Math.exp(this.expTerm*this.chargeValue*psiL/2.0D); + double gamma = (expPart - 1.0D)/(expPart + 1.0D); + double gammaExp = gamma*Math.exp(-kappa*xDistance); + potAtX = 2.0D*Math.log((1.0D + gammaExp)/(1.0D - gammaExp))/(this.expTerm*this.chargeValue); + } + else{ + // asymmetric electrolye + // Create instance of integration function + FunctionPatX func = new FunctionPatX(); + func.numOfIons = this.numOfIons; + func.termOne = 2.0D*Fmath.N_AVAGADRO*Fmath.K_BOLTZMANN*this.tempK/(Fmath.EPSILON_0*this.epsilon); + func.expTerm = this.expTerm ; + func.bulkConcn = this.bulkConcn; + func.charges = this.charges; + int nPointsGQ = 2000; // number of points in the numerical integration + + // bisection procedure + double psiXlow = 0.0; + double pFuncLow = xDistance - Integration.trapezium(func, psiXlow, psiL, nPointsGQ); + double psiXhigh = psiL; + double pFuncHigh = xDistance - Integration.trapezium(func, psiXhigh, psiL, nPointsGQ); + if(pFuncHigh*pFuncLow>0.0D)throw new IllegalArgumentException("root not bounded"); + double check = Math.abs(xDistance)*1e-2; + boolean test = true; + double psiXmid = 0.0D; + double pFuncMid = 0.0D; + int nIter = 0; + + while(test){ + psiXmid = (psiXlow + psiXhigh)/2.0D; + pFuncMid = xDistance - Integration.trapezium(func, psiXmid, psiL, nPointsGQ); + if(Math.abs(pFuncMid)<=check){ + potAtX = psiXmid; + test = false; + } + else{ + nIter++; + if(nIter>10000){ + System.out.println("Class: GouyChapmanStern\nMethod: getPotentialAtX\nnumber of iterations exceeded in outer bisection\ncurrent value of psi(x) returned"); + potAtX = psiXmid; + test = false; + } + else{ + if(pFuncLow*pFuncMid>0.0D){ + psiXlow = psiXmid; + pFuncLow = pFuncMid; + } + else{ + psiXhigh = psiXmid; + pFuncHigh = pFuncMid; + } + } + } + } + } + return potAtX; + } + + // Get concentrations at a distance, x, from the interface(M) + public double[] getConcnsAtX(double xDistance){ + if(!this.psi0set && !this.sigmaSet)throw new IllegalArgumentException("Neither a surface potential nor a surface charge/density have been entered"); + if(this.sigmaSet && !this.psi0set)this.getSurfacePotential(); + if(this.psi0set && !this.sigmaSet)this.getSurfaceChargeDensity(); + + double[] conc = new double[this.numOfIons]; + if(this.sternOption && xDistance<this.sternDelta){ + for(int i=0; i<this.numOfIons; i++)conc[i] = 0.0D; + } + else{ + double psi = this.getPotentialAtX(xDistance); + for(int i=0; i<this.numOfIons; i++)conc[i] = bulkConcn[i]*Math.exp(-this.expTerm*this.charges[i]*psi); + } + return conc; + } + + // Get initial concentrations (M) + public double[] getInitConcns(){ + if(!this.psi0set && !this.sigmaSet)unpack(); + double[] conc = this.initConcn.clone(); + for(int i=0; i<this.numOfIons; i++)conc[i] *= 1e-3; + return conc; + } + + // Get equilibrium bulk concentrations (M) + public double[] getBulkConcns(){ + if(!this.psi0set && !this.sigmaSet)throw new IllegalArgumentException("Neither a surface potential nor a surface charge/density have been entered"); + if(this.sigmaSet && !this.psi0set)this.getSurfacePotential(); + if(this.psi0set && !this.sigmaSet)this.getSurfaceChargeDensity(); + + double[] conc = this.bulkConcn.clone(); + for(int i=0; i<this.numOfIons; i++)conc[i] *= 1e-3; + return conc; + } + + // Get adsorbed ion concentrations (mol m-2) + public double[] getSiteConcns(){ + if(!this.psi0set && !this.sigmaSet)throw new IllegalArgumentException("Neither a surface potential nor a surface charge/density have been entered"); + if(this.sigmaSet && !this.psi0set)this.getSurfacePotential(); + if(this.psi0set && !this.sigmaSet)this.getSurfaceChargeDensity(); + + return this.siteConcn; + } + + // Calculate the surface potential + // Gouy-Chapman-Stern - Specific absorption - symmetric electrolyte + private double surfacePotential2(double sigma){ + double surPot = 0.0D; // temporary values of the surface potential + + // INITIAL ESTIMATES + // Ignore specific absorption + double diffPot = Fmath.asinh(sigma/Math.sqrt(this.eightTerm*this.electrolyteConcn))/(this.chargeValue*this.expTermOver2); + // Recalculate total charge with adsorption + // double totCharge = getSurfaceChargeDensity(diffPot); + double pLow = 0.0D; + double pHigh = 0.0D; + if(diffPot>0.0D){ + pHigh = 2.0D*diffPot; + } + else{ + pLow = 2.0D*diffPot; + } + // call bisection method + surPot = surfacePotentialBisection(pLow, pHigh, sigma, 2); + + return surPot; + } + + + // Bisection method for surfacePotential2 and surfacePotential3 + // n = 2 for surfacePotential2 and n = 3 for surfacePotential3 + private double surfacePotentialBisection(double pLow, double pHigh, double sigma, int n){ + double surPot = 0.0D; // temporary values of the surface potential + + // Bisection method converging on sigma calculated = true sigma + boolean testC = true; + int testCiter = 0; + int testCmax = 10; + double pDiff = pHigh-pLow; + double cLow = cFunction(pLow, sigma); + double cHigh = cFunction(pHigh, sigma); + while(testC){ + if(pHigh*pLow>0.0D){ + testCiter++; + if(testCiter>testCmax)throw new IllegalArgumentException("root not bounded after " + testCiter + "expansions"); + pLow -= pDiff; + pHigh += pDiff; + cLow = cFunction(pLow, sigma); + cHigh = cFunction(pHigh, sigma); + } + else{ + testC=false; + } + } + double check = Math.abs(sigma)*1e-6; + boolean test = true; + double cMid = 0.0D; + int nIter = 0; + while(test){ + surPot = (pLow + pHigh)/2.0D; + cMid = this.cFunction(surPot, sigma); + if(Math.abs(cMid)<=check){ + test = false; + } + else{ + nIter++; + if(nIter>10000){ + System.out.println("Class: GouyChapmanStern\nMethod: surfacePotential"+n +"\nnumber of iterations exceeded in bisection\ncurrent value of sigma returned"); + test = false; + } + if(cMid*cHigh>0){ + pHigh = surPot; + cHigh = cMid; + } + else{ + pLow = surPot; + cLow = cMid; + } + } + } + + return surPot; + } + + // Function to calculate difference between set value of the charge density and the estimated value for a current estimate of the surface potential + private double cFunction(double psi, double sigma){ + double sigmaEst = this.calcSurfaceChargeDensity(psi); + return sigmaEst - sigma; + } + + // Gouy-Chapman-Stern - Specific absorption - asymmetric electrolyte + private double surfacePotential3(double sigma){ + double surPot = 0.0D; // temporary values of the surface potential + + // INITIAL ESTIMATES + // Ignore specific absorption + double diffPot = Fmath.asinh(sigma/Math.sqrt(this.eightTerm*this.electrolyteConcn))/(this.chargeValue*this.expTermOver2); + // Recalculate total charge with adsorption + // double totCharge = getSurfaceChargeDensity(diffPot); + double pLow = 0.0D; + double pHigh = 0.0D; + if(diffPot>0.0D){ + pHigh = 2.0D*diffPot; + } + else{ + pLow = 2.0D*diffPot; + } + // call bisection method + surPot = surfacePotentialBisection(pLow, pHigh, sigma, 3); + + return surPot; + } +} + + + + + diff --git a/src/main/java/flanagan/physprop/IonicRadii.java b/src/main/java/flanagan/physprop/IonicRadii.java new file mode 100755 index 0000000000000000000000000000000000000000..a572edf85d0462053c041afc32d83a489c4ccad2 --- /dev/null +++ b/src/main/java/flanagan/physprop/IonicRadii.java @@ -0,0 +1,299 @@ +/* +* Class IonicRadii +* +* Methods for returning the non-hydrated ionic radius +* or the hydrated ionic radius of an entered ion +* +* Bare radii taken from: +* Indiana University Molecular Structure Center, Retrieved on 1st November 2004 from the World Wide Web: +* http://www.iumsc.indiana.edu/radii.html +* Their source is: +* Shannon,R.D. (1976) `Revised effective ionic radii in halides and chalcogenides', Acta Cryst. A32, 751. +* +* WRITTEN BY: Michael Thomas Flanagan +* +* DATE: November 2004 +* UPDATE: 22 May 2005, 11 December 2007 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's JAVA library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/IonicRadii.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2004 - 2008 Michael Thomas Flanagan +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.physprop; + +import javax.swing.*; + +public class IonicRadii{ + + // ion symbols for non-hydrated ion radii + private static String[] ions1 = {"Ag+", "Al+++", "Au+", "Au+++", "Ba++", "Be++", "Bi+++", "Ca++", "Cd++", "Ce+++", "Ce++++", "Co++ ls", "Co++ hs", "Co+++ ls", "Co+++ hs", "Cr++ ls", "Cr++ hs", "Cr+++", "Cs+", "Cu+", "Cu++", "Dy+++", "Er+++", "Eu++", "Eu+++", "Fe++ ls", "Fe++ hs", "Fe+++ ls", "Fe+++ hs", "Ga+++", "Gd+++", "Hf++++", "Hg+", "Hg++", "Ho+++", "In+++", "Ir+++", "K+", "La+++", "Li+", "Lu+++", "Mg++", "Mn++ ls", "Mn++ hs", "Mn+++ ls", "Mn+++ hs", "Mo+++", "Na+", "Nb+++", "Nd+++", "Ni++", "Pb++", "Pd++", "Pm+++", "Pr+++", "Pt++", "Rb+", "Rh+++", "Ru+++", "Sb+++", "Sc+++", "Sm+++", "Sr++", "Ta+++", "Tb+++", "Th++++", "Ti++", "Ti+++", "Ti++++", "Tl+", "Tl+++", "Tm+++", "U+++", "U++++", "V++", "V+++", "Y+++", "Yb++", "Yb+++", "Zn++", "Zr++++", "Br-", "Cl-", "F-", "H-", "I-", "O--", "S--", "Se--", "Te--", "OH-"}; + private static String[] ions2 = {"Ag1+", "Al3+", "Au1+", "Au3+", "Ba2+", "Be2+", "Bi3+", "Ca2+", "Cd2+", "Ce3+", "Ce4+", "Co2+ ls", "Co2+ hs", "Co3+ ls", "Co3+ hs", "Cr2+ ls", "Cr2+ hs", "Cr3+", "Cs1+", "Cu1+", "Cu2+", "Dy3+", "Er3+", "Eu2+", "Eu3+", "Fe2+ ls", "Fe2+ hs", "Fe3+ ls", "Fe3+ hs", "Ga3+", "Gd3+", "Hf4+", "Hg1+", "Hg2+", "Ho3+", "In3+", "Ir3+", "K1+", "La3+", "Li1+", "Lu3+", "Mg2+", "Mn2+ ls", "Mn2+ hs", "Mn3+ ls", "Mn3+ hs", "Mo3+", "Na1+", "Nb3+", "Nd3+", "Ni2+", "Pb2+", "Pd2+", "Pm3+", "Pr3+", "Pt2+", "Rb1+", "Rh3+", "Ru3+", "Sb3+", "Sc3+", "Sm3+", "Sr2+", "Ta3+", "Tb3+", "Th4+", "Ti2+", "Ti3+", "Ti4+", "Tl1+", "Tl3+", "Tm3+", "U3+", "U4+", "V2+", "V3+", "Y3+", "Yb2+", "Yb3+", "Zn2+", "Zr4+", "Br1-", "Cl1-", "F1-", "H1-", "I1-", "O2-", "S2-", "Se2-", "Te2-", "OH1-"}; + private static String[] ions3 = {"Ag+1", "Al+3", "Au+1", "Au+3", "Ba+2", "Be+2", "Bi+3", "Ca+2", "Cd+2", "Ce+3", "Ce+4", "Co+2 ls", "Co+2 hs", "Co+3 ls", "Co+3 hs", "Cr+2 ls", "Cr+2 hs", "Cr+3", "Cs+1", "Cu+1", "Cu+2", "Dy+3", "Er+3", "Eu+2", "Eu+3", "Fe+2 ls", "Fe+2 hs", "Fe+3 ls", "Fe+3 hs", "Ga+3", "Gd+3", "Hf+4", "Hg+1", "Hg+2", "Ho+3", "In+3", "Ir+3", "K+1", "La+3", "Li+1", "Lu+3", "Mg+2", "Mn+2 ls", "Mn+2 hs", "Mn+3 ls", "Mn+3 hs", "Mo+3", "Na+1", "Nb+3", "Nd+3", "Ni+2", "Pb+2", "Pd+2", "Pm+3", "Pr+3", "Pt+2", "Rb+1", "Rh+3", "Ru+3", "Sb+3", "Sc+3", "Sm+3", "Sr+2", "Ta+3", "Tb+3", "Th+4", "Ti+2", "Ti+3", "Ti+4", "Tl+1", "Tl+3", "Tm+3", "U+3", "U+4", "V+2", "V+3", "Y+3", "Yb+2", "Yb+3", "Zn+2", "Zr+4", "Br-1", "Cl-1", "F-1", "H-1", "I-1", "O-2", "S-2", "Se-2", "Te-2", "OH-1"}; + private static String[] ions4 = {"Ag(+)", "Al(+++)", "Au(+)", "Au(+++)", "Ba(++)", "Be(++)", "Bi(+++)", "Ca(++)", "Cd(++)", "Ce(+++)", "Ce(++++)", "Co(++) ls", "Co(++) hs", "Co(+++) ls", "Co(+++) hs", "Cr(++) ls", "Cr(++) hs", "Cr(+++)", "Cs(+)", "Cu(+)", "Cu(++)", "Dy(+++)", "Er(+++)", "Eu(++)", "Eu(+++)", "Fe(++) ls", "Fe(++) hs", "Fe(+++) ls", "Fe(+++) hs", "Ga(+++)", "Gd(+++)", "Hf(++++)", "Hg(+)", "Hg(++)", "Ho(+++)", "In(+++)", "Ir(+++)", "K(+)", "La(+++)", "Li(+)", "Lu(+++)", "Mg(++)", "Mn(++) ls", "Mn(++) hs", "Mn(+++) ls", "Mn(+++) hs", "Mo(+++)", "Na(+)", "Nb(+++)", "Nd(+++)", "Ni(++)", "Pb(++)", "Pd(++)", "Pm(+++)", "Pr(+++)", "Pt(++)", "Rb(+)", "Rh(+++)", "Ru(+++)", "Sb(+++)", "Sc(+++)", "Sm(+++)", "Sr(++)", "Ta(+++)", "Tb(+++)", "Th(++++)", "Ti(++)", "Ti(+++)", "Ti(++++)", "Tl(+)", "Tl(+++)", "Tm(+++)", "U(+++)", "U(++++)", "V(++)", "V(+++)", "Y(+++)", "Yb(++)", "Yb(+++)", "Zn(++)", "Zr(++++)", "Br(-)", "Cl(-)", "F(-)", "H(-)", "I(-)", "O(--)", "S(--)", "Se(--)", "Te(--)", "OH(-)"}; + private static String[] ions5 = {"Ag(1+)", "Al(3+)", "Au(1+)", "Au(3+)", "Ba(2+)", "Be(2+)", "Bi(3+)", "Ca(2+)", "Cd(2+)", "Ce(3+)", "Ce(4+)", "Co(2+) ls", "Co(2+) hs", "Co(3+) ls", "Co(3+) hs", "Cr(2+) ls", "Cr(2+) hs", "Cr(3+)", "Cs(1+)", "Cu(1+)", "Cu(2+)", "Dy(3+)", "Er(3+)", "Eu(2+)", "Eu(3+)", "Fe(2+) ls", "Fe(2+) hs", "Fe(3+) ls", "Fe(3+) hs", "Ga(3+)", "Gd(3+)", "Hf(4+)", "Hg(1+)", "Hg(2+)", "Ho(3+)", "In(3+)", "Ir(3+)", "K(1+)", "La(3+)", "Li(1+)", "Lu(3+)", "Mg(2+)", "Mn(2+) ls", "Mn(2+) hs", "Mn(3+) ls", "Mn(3+) hs", "Mo(3+)", "Na(1+)", "Nb(3+)", "Nd(3+)", "Ni(2+)", "Pb(2+)", "Pd(2+)", "Pm(3+)", "Pr(3+)", "Pt(2+)", "Rb(1+)", "Rh(3+)", "Ru(3+)", "Sb(3+)", "Sc(3+)", "Sm(3+)", "Sr(2+)", "Ta(3+)", "Tb(3+)", "Th(4+)", "Ti(2+)", "Ti(3+)", "Ti(4+)", "Tl(1+)", "Tl(3+)", "Tm(3+)", "U(3+)", "U(4+)", "V(2+)", "V(3+)", "Y(3+)", "Yb(2+)", "Yb(3+)", "Zn(2+)", "Zr(4+)", "Br(1-)", "Cl(1-)", "F(1-)", "H(1-)", "I(1-)", "O(2-)", "S(2-)", "Se(2-)", "Te(2-)", "OH(1-)"}; + private static String[] ions6 = {"Ag(+1)", "Al(+3)", "Au(+1)", "Au(+3)", "Ba(+2)", "Be(+2)", "Bi(+3)", "Ca(+2)", "Cd(+2)", "Ce(+3)", "Ce(+4)", "Co(+2) ls", "Co(+2) hs", "Co(+3) ls", "Co(+3) hs", "Cr(+2) ls", "Cr(+2) hs", "Cr(+3)", "Cs(+1)", "Cu(+1)", "Cu(+2)", "Dy(+3)", "Er(+3)", "Eu(+2)", "Eu(+3)", "Fe(+2) ls", "Fe(+2) hs", "Fe(+3) ls", "Fe(+3) hs", "Ga(+3)", "Gd(+3)", "Hf(+4)", "Hg(+1)", "Hg(+2)", "Ho(+3)", "In(+3)", "Ir(+3)", "K(+1)", "La(+3)", "Li(+1)", "Lu(+3)", "Mg(+2)", "Mn(+2) ls", "Mn(+2) hs", "Mn(+3) ls", "Mn(+3) hs", "Mo(+3)", "Na(+1)", "Nb(+3)", "Nd(+3)", "Ni(+2)", "Pb(+2)", "Pd(+2)", "Pm(+3)", "Pr(+3)", "Pt(+2)", "Rb(+1)", "Rh(+3)", "Ru(+3)", "Sb(+3)", "Sc(+3)", "Sm(+3)", "Sr(+2)", "Ta(+3)", "Tb(+3)", "Th(+4)", "Ti(+2)", "Ti(+3)", "Ti(+4)", "Tl(+1)", "Tl(+3)", "Tm(+3)", "U(+3)", "U(+4)", "V(+2)", "V(+3)", "Y(+3)", "Yb(+2)", "Yb(+3)", "Zn(+2)", "Zr(+4)", "Br(-1)", "Cl(-1)", "F(-1)", "H(-1)", "I(-1)", "O(-2)", "S(-2)", "Se(-2)", "Te(-2)", "OH(-1)"}; + + // spin state indicators + private static boolean[] spins = {false, false, false, false, false, false, false, false, false, false, false, true, true, true, true, true, true,false, false, false, false, false, false, false, false, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, true, true,false, false, false, false, false, false, false, false, false, false, false, false, false, false,false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}; + + // charges + private static int[] ionCharge = {1, 3, 1, 3, 2, 2, 3, 2, 2, 3, 4, 2, 2, 3, 3, 2, 2, 3, 1, 1, 2, 3, 3, 2, 3, 2, 2, 3, 3, 3, 3, 4, 1, 2, 3, 3, 3, 1, 3, 1, 3, 2, 2, 2, 3, 3, 3, 1, 3, 3, 2, 2, 2, 3, 3, 2, 1, 3, 3, 3, 3, 3, 2, 3, 3, 4, 2, 3, 4, 1, 3, 3, 3, 4, 2, 3, 3, 2, 3, 2, 4, -1, -1, -1, -1, -1, -2, -2, -2, -2, -1}; + + // non-hydrated ionic radii (pm) + private static double radii[] = {129, 67.5, 151, 99, 149, 59, 117, 114, 109, 115, 101, 79, 88.5, 68.5, 75, 87, 94, 75.5, 181, 91, 87, 105.2, 103, 131, 108.7, 75, 92, 69, 78.5, 76, 107.8, 85, 133, 116, 104.1, 94, 82, 152, 117.2, 90, 100.1, 86, 81, 97, 72, 78.5, 83, 116, 86, 112.3, 83, 133, 100, 111, 113, 94, 166, 80.5, 82, 90, 88.5, 109.8, 132, 86, 106.3, 108, 100, 81, 74.5, 164, 102.5, 102, 116.5, 103 ,93, 78, 104, 116, 100.8, 88, 86, 167, 182, 119, 139, 206, 126, 170, 184, 207, 120}; + + // ion symbols for hydrated ion radii + private static String[] hydratedIons1 = {"Ag+", "Al+++", "Be++", "Ca++", "Cd++", "Cs+", "K+", "Li+", "Mg++", "Na+", "Pb++", "Rb+", "Tl+", "Zn++", "H30+", "NH4+", "Cl-", "Br-", "F-", "I-", "NO3-", "OH-"}; + private static String[] hydratedIons2 = {"Ag1+", "Al3+", "Be2+", "Ca2+", "Cd2+", "Cs1+", "K1+", "Li1+", "Mg2+", "Na1+", "Pb2+", "Rb1+", "Tl1+", "Zn2+", "H301+", "NH41+", "Cl1-", "Br1-", "F1-", "I1-", "NO31-", "OH1-"}; + private static String[] hydratedIons3 = {"Ag+1", "Al+3", "Be+2", "Ca+2", "Cd+2", "Cs+1", "K+1", "Li+1", "Mg+2", "Na+1", "Pb+2", "Rb+1", "Tl+1", "Zn+2", "H30+1", "NH4+1", "Cl-1", "Br-1", "F-1", "I-1", "NO3-1", "OH-1"}; + private static String[] hydratedIons4 = {"Ag(+)", "Al(+++)", "Be(++)", "Ca(++)", "Cd(++)", "Cs(+)", "K(+)", "Li(+)", "Mg(++)", "Na(+)", "Pb(++)", "Rb(+)", "Tl(+)", "Zn(++)", "H30(+)", "NH4(+)", "Cl(-)", "Br(-)", "F(-)", "I(-)", "NO3(-)", "OH(-)"}; + private static String[] hydratedIons5 = {"Ag(1+)", "Al(3+)", "Be(2+)", "Ca(2+)", "Cd(2+)", "Cs(1+)", "K(1+)", "Li(1+)", "Mg(2+)", "Na(1+)", "Pb(2+)", "Rb(1+)", "Tl(1+)", "Zn(2+)", "H30(1+)", "NH4(1+)", "Cl(1-)", "Br(1-)", "F(1-)", "I(1-)", "NO3(1-)", "OH(1-)"}; + private static String[] hydratedIons6 = {"Ag(+1)", "Al(+3)", "Be(+2)", "Ca(+2)", "Cd(+2)", "Cs(+1)", "K(+1)", "Li(+1)", "Mg(+2)", "Na(+1)", "Pb(+2)", "Rb(+1)", "Tl(+1)", "Zn(+2)", "H30(+1)", "NH4(+1)", "Cl(-1)", "Br(-1)", "F(-1)", "I(-1)", "NO3(-1)", "OH(-1)"}; + + // hydated ionic radii (pm) + private static double hydratedRadii[] = {341.0, 480.0, 459.0, 412.0, 426.0, 329.0, 331.0, 382.0, 428.0, 358.0, 401.0, 329.0, 330.0, 430.0, 280.0, 331.0, 332.0, 332.0, 330.0, 352.0, 340.0, 300.0}; + + private static int nIons = 91; // number of ions listed for non-hydrated radii + private static int nHydratedIons = 22; // number of ions listed for hydrated radii + + // variables used in methods + // String ion - symbol of current ion without spin indicator + // String fullIon - symbol of current ion with spin indicator if available + // String spin - spin value of current ion if option available + // boolean spinSet = true when spin state is set + + // Method to return an ionic radius for ion with low and high spin states + public static double radius(String ion, String spin){ + boolean spinSet = false; + spin = spin.trim(); + + if(spin.equals("ls") || spin.equals("low") || spin.equals("low spin") || spin.equals("LS")){ + spin = "ls"; + } + else{ + if(spin.equals("hs") || spin.equals("high") || spin.equals("high spin") || spin.equals("HS")){ + spin = "hs"; + } + else{ + throw new IllegalArgumentException("spin state must be entered as ls or hs not as " + spin); + } + } + spinSet = true; + ion = ion.trim(); + String fullIon = ion + " " + spin; + return radiusCalc(fullIon, spinSet); + } + + // Method to return an ionic radius - no spin state set + public static double radius(String ion){ + boolean spinSet = false; + return radiusCalc(ion, spinSet); + } + + // Private method to retrieve an ionic radius + private static double radiusCalc(String ion, boolean spinSet){ + String fullIon = ion.trim(); + if(!spinSet)ion = fullIon; + + boolean test0 = true; + boolean test1 = false; + int ii = 0; + double radius = 0.0D; + + // check entered ion against ion list + while(test0){ + if(IonicRadii.compareBare(fullIon, ii)){ + test0 = false; + test1 = true; + radius = IonicRadii.radii[ii]*1e-12; + } + else{ + ii++; + if(ii>=IonicRadii.nIons)test0=false; + } + } + + // check if hs or ls is needed and is missing + if(!test1 && !spinSet){ + test0=true; + ii=0; + while(test0){ + if(compareSubstringBare(ion, ii) && IonicRadii.spins[ii]){ + test0 = false; + test1 = true; + boolean test2 = true; + String enqTitle = ion+" may be low spin or high spin"; + Object[] options = { "low spin", "high spin" }; + while(test2){ + int opt = JOptionPane.showOptionDialog(null, "Click appropriate box", enqTitle, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,null, options, options[0]); + + if(opt==0){ + radius = IonicRadii.radii[ii]*1e-12; + test2 = false; + } + else{ + if(opt==1){ + radius = IonicRadii.radii[ii+1]*1e-12; + test2 = false; + } + else{ + System.out.println("You must click either low spin or high spin"); + } + } + } + } + else{ + ii++; + if(ii>=IonicRadii.nIons)test0=false; + } + } + } + + // check if hs or ls has been entered and is not appropriate to the ion entered + if(!test1){ + if(spinSet){ + test0 = true; + ii = 0; + while(test0){ + if(IonicRadii.compareBare(ion, ii)){ + test0 = false; + test1 = true; + radius = IonicRadii.radii[ii]*1e-12; + System.out.println(ion + " does not have low and high spin states listed"); + System.out.println("Single availabe listed radius was used"); + } + else{ + ii++; + if(ii>=IonicRadii.nIons)test0=false; + } + } + } + } + + // Abort if entered ion was not found in lists + if(!test1){ + System.out.println("Class: IonicRadii\nMethod: radius\n" + fullIon + " was not found in the lists of non-hydrated radii"); + System.out.println("0.0D returned"); + } + spinSet = false; + return radius; + } + + // Compares entered ion with all lists of ions for non-hydrated radii values + public static boolean compareBare(String ion, int ii){ + boolean test = false; + if(ion.equals(IonicRadii.ions1[ii])||ion.equals(IonicRadii.ions2[ii])||ion.equals(IonicRadii.ions3[ii])||ion.equals(IonicRadii.ions4[ii])||ion.equals(IonicRadii.ions5[ii])||ion.equals(IonicRadii.ions6[ii])){ + test = true; + } + return test; + } + + // Compares entered ion as a substring, e.g. without ls or hs indicator, with all lists of ions for non-hydrated radii values + public static boolean compareSubstringBare(String ion, int ii){ + boolean test = false; + if(IonicRadii.ions1[ii].indexOf(ion)>-1||IonicRadii.ions2[ii].indexOf(ion)>-1||IonicRadii.ions3[ii].indexOf(ion)>-1||IonicRadii.ions4[ii].indexOf(ion)>-1||IonicRadii.ions5[ii].indexOf(ion)>-1||IonicRadii.ions6[ii].indexOf(ion)>-1){ + test = true; + } + return test; + } + + // Method to return a hydrated ionic radius + public static double hydratedRadius(String ion){ + ion = ion.trim(); + + boolean test0 = true; + boolean test1 = false; + int i = 0; + double radius = 0.0D; + + // check entered ion against ion list + while(test0){ + if(IonicRadii.compareHydrated(ion, i)){ + test0 = false; + test1 = true; + radius = hydratedRadii[i]*1e-12; + } + else{ + i++; + if(i>=nHydratedIons)test0=false; + } + } + + // Abort if entered ion was not found in lists + if(!test1){ + System.out.println("Class: IonicRadii\nMethod: hydratedRadius\n"+ion + " was not found in the lists of hydrated radii"); + System.out.println("0.0D returned"); + } + + return radius; + } + + + // Compares entered ion with all lists of ions for hydrated radii values + public static boolean compareHydrated(String ion, int ii){ + boolean test = false; + if(ion.equals(IonicRadii.hydratedIons1[ii])||ion.equals(IonicRadii.hydratedIons2[ii])||ion.equals(IonicRadii.hydratedIons3[ii])||ion.equals(IonicRadii.hydratedIons4[ii])||ion.equals(IonicRadii.hydratedIons5[ii])||ion.equals(IonicRadii.hydratedIons6[ii])){ + test = true; + } + return test; + } + + // Compares entered ion as a substring, e.g. without ls or hs indicator, with all lists of ions for hydrated radii values + public static boolean compareSubstringHydrated(String ion, int ii){ + boolean test = false; + if(IonicRadii.hydratedIons1[ii].indexOf(ion)>-1||IonicRadii.hydratedIons2[ii].indexOf(ion)>-1||IonicRadii.hydratedIons3[ii].indexOf(ion)>-1||IonicRadii.hydratedIons4[ii].indexOf(ion)>-1||IonicRadii.hydratedIons5[ii].indexOf(ion)>-1||IonicRadii.hydratedIons6[ii].indexOf(ion)>-1){ + test = true; + } + return test; + } + + // Method to return the charge on the ion + public static int charge(String ion){ + ion = ion.trim(); + + boolean test0 = true; + boolean test1 = false; + int i = 0; + int charge = 0; + + // check entered ion against ion list + while(test0){ + if(IonicRadii.compareBare(ion, i)){ + test0 = false; + test1 = true; + charge = ionCharge[i]; + } + else{ + i++; + if(i>=nIons)test0=false; + } + } + + // Abort if entered ion was not found in lists + if(!test1){ + System.out.println("Class: IonicRadii\nMethod: charge\n"+ion + " was not found in the lists of non-hydrated ions"); + System.out.println("0 returned"); + } + + return charge; + } +} + + + + + diff --git a/src/main/java/flanagan/physprop/Pva.java b/src/main/java/flanagan/physprop/Pva.java new file mode 100755 index 0000000000000000000000000000000000000000..55feb6ca5d7bb03aca5b372a8c31b24ef5b72bc3 --- /dev/null +++ b/src/main/java/flanagan/physprop/Pva.java @@ -0,0 +1,121 @@ +/* +* Pva Class +* +* Methods for returning the physical properties of +* aqueous polyvinylalcohol (pva) solutions: +* viscosity, density, refractive index, +* diffusion coefficient and specific volume. +* +* Reference: Pritchard, J. G., Poly(vinyl alcohol) : basic properties and +* uses, Macdonald & Co, London, 1970. +* UCL DMS Watson Library location: CHEMISTRY D 297 PRI. +* +* Author: Dr Michael Thomas Flanagan. +* +* Created: July 2003 +* Updated: 1 July 2003 and 2 May 2004 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Pva.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) May 2004 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.physprop; + +import flanagan.math.Fmath; + +public class Pva{ + + // METHODS + // Returns the viscosity (Pa s) of aqueous pva solutions as a function of the + // g/l pva concentration (concn), the temperature [Celsius](temp) and the + // molecualr weight of the pva (molwt). + // Empirical equation from Poly(vinyl alcohol): basic properties and uses by J G Pritchard (1970) + public static double viscosity(double concn, double molwt, double temp){ + + double intVisc30, intVisc20, intViscT, spViscT, waterViscT, viscosity, concndlpg; + + intVisc30 = 4.53e-4*Math.pow(molwt, 0.64); + intVisc20 = intVisc30*1.07; + intViscT = intVisc20*Math.pow(1.07, -(temp-20)/10); + concndlpg = concn/10.0; + spViscT = concndlpg*(intViscT + 0.201*concndlpg*Math.pow(intViscT, 2.28)); + waterViscT = Water.viscosity(temp); + viscosity = (spViscT + 1.0)*waterViscT; + + return viscosity; + } + + // Returns the density (kg/m^3) of aqueous pva solutions, at 30 C, as a function of + // g/l pva concentration (concn) and the molecular weight + // Empirical equation from Poly(vinyl alcohol): basic properties and uses by J G Pritchard (1970) + public static double density(double concn, double molwt){ + + double density; + + concn=concn/10.0; + density = 1000*(0.99565 +(0.00248 - 1.09/molwt)*concn + (0.000064 - 0.39/molwt)*concn*concn); + + return density; + } + + // Returns the specific volume (kg/m^3) of pva in aqueous solution + // Data Poly(vinyl alcohol): basic properties and uses by J G Pritchard (1970) + public static double specificVolume(){ + return 0.000765; + } + + // returns the diffusion coefficient (m^2 s^-1) of pva in aqueous solution + // as a function of the g/l pva concentration (concn), pva molecular weight (molwt) + // and temperature (temp) [Celsius]. + public static double diffCoeff(double concn, double molwt, double temp){ + + double diffcoef, f, viscosity, specvol, vol, radius, tempa; + + tempa = temp-Fmath.T_ABS; + + viscosity = Pva.viscosity(concn, molwt, temp); + specvol = Pva.specificVolume(); + vol = molwt*specvol/(Fmath.N_AVAGADRO*1000); + radius=Math.pow(3.0*vol/(4.0*Math.PI),1.0/3.0); + + f=6.0*Math.PI*viscosity*radius; + diffcoef=Fmath.K_BOLTZMANN*tempa/f; + + return diffcoef; + } + + // Returns the refractive index of pva solutions as a function of g/l pva concentration + // Data Poly(vinyl alcohol): basic properties and uses by J G Pritchard (1970) + // pva refractive index increment fitted to modified Cauchy equation: + // dn = 1 + a1*(1 + b1/(lambda*lambda)) + // concn g/l concentration of pva + // temp temperature (degree Celsius) (t = 30C for original pva increment calculation) + // wavl wavelength in metres + public static double refractIndex(double concn, double wavl, double temp) + { + double refind, rfwater, rfincr; + double a1=-0.998419, b1=-1.87778e-17; + + rfwater = Water.refractIndex(wavl, temp); + rfincr = 1.0 + a1*(1.0 + b1/Math.pow(wavl, 2)); + refind = rfwater + rfincr*concn/10.0; + + return refind; + } + +} \ No newline at end of file diff --git a/src/main/java/flanagan/physprop/RefrIndex.java b/src/main/java/flanagan/physprop/RefrIndex.java new file mode 100755 index 0000000000000000000000000000000000000000..247cd296a64fbcee990b3e0ed2743654166327ea --- /dev/null +++ b/src/main/java/flanagan/physprop/RefrIndex.java @@ -0,0 +1,177 @@ +/* +* RefrIndex Class (deprecated) +* +* Methods for returning the refractive index, for a given wavelength, +* of gold, silver, fused quartz, crown glass, float glass, +* microscope slide glass, polymethacrylate, air, +* water, sodium chloride solutions, sucrose solutions, PVA solutions. +* Methods for calculating refractive index of mixtures and interconverting +* absorption coefficients and imaginary refractive indices. +* +* Methods for returning the physical properties of water: +* viscosity, density, refractive index, +* electrical permittivity, molecular weight. +* +* Author: Dr Michael Thomas Flanagan. +* +* Created: July 2003 +* Updated: 1 July 2003, 1 May 2004, +* REPLACED:28 February 2006 - Replaced by RefractiveIndex in the optics section of this library +* The methods in RefrIndex now call the corresponding methods in RefractiveIndex +* RefrIndex has been retained to ensure backward compatibility +* +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/RefractiveIndex.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* http://www.ee.ucl.ac.uk/~mflanaga/java/RefrIndex.html (deprecated) +* +* Copyright (c) July 2003 - May 2004 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.physprop; + +import flanagan.optics.RefractiveIndex; +import flanagan.complex.Complex; + +public class RefrIndex{ + + // METHODS + // Returns a complex refractive index given the real part of the refractive index (riReal), + // the extinction coefficient (extCoeff)and the concentration of the absorbing species (concn) + // and the wavelength (wavl). For a pure material with a given absorption coefficient set concn + // to unity and extCoeff to the value of the absorption coefficient. + // The units of the concentration, the absorption coefficient and the wavelength should match. + public static Complex absToComplex(double riReal, double extCoeff, double concn, double wavl){ + return RefractiveIndex.absToComplex(riReal, extCoeff, concn, wavl); + } + + // Returns the absorption coefficient ( units - reciprocal metres) that corresponds + // to the imaginary part of a complex refractive index (riImag) at a wavelength wavl (metres) + public static double imagToAbs(double riImag, double wavl){ + return RefractiveIndex.imagToAbs(riImag, wavl); + } + + // Returns the complex refractive index of GOLD for a given wavelength (in metres) + // Interpolation - natural cubic spline + // Data - P.B. Johnson and R.W. Christy, Phys. Rev. B. 6(12) 4370-4379, 1972 + public static Complex gold(double wavelength){ + return RefractiveIndex.gold(wavelength); + } + + // Returns the complex refractive index of SILVER for a given wavelength (in metres) + // Interpolation - natural cubic spline + // Data - P.B. Johnson and R.W. Christy, Phys. Rev. B. 6(12) 4370-4379, 1972 + public static Complex silver(double wavelength){ + return RefractiveIndex.silver(wavelength); + } + + // Returns the real refractive index of FUSED QUARTZ for a given wavelength (in metres) + // Interpolation - natural cubic spline + // Extrapolation - Cauchy equation + public static double quartz(double wavelength){ + return RefractiveIndex.quartz(wavelength); + } + + // Returns the real refractive index of LAF78847 CROWN GLASS for a given wavelength (in metres) + // Interpolation - natural cubic spline + // Extrapolation - Cauchy equation + public static double crownGlass(double wavelength){ + return RefractiveIndex.crownGlass(wavelength); + } + + // Returns the real refractive index of PILKINGTON PERMABLOC FLOAT GLASS for a given wavelength (in metres) + // Interpolation - natural cubic spline + // Extrapolation - Cauchy equation + public static double floatGlass(double wavelength){ + + return RefractiveIndex.floatGlass(wavelength); + } + + // Returns the real refractive index of CHANCE POPPER MICROSCOPE SLIDE GLASS for a given wavelength (in metres) + // Interpolation - natural cubic spline + // Extrapolation - Cauchy equation + public static double microSlideGlass(double wavelength){ + return RefractiveIndex.microscopeSlideGlass(wavelength); + } + + // Returns the real refractive index of POLYMETHACRYLATE for a given wavelength (in metres) + // Interpolation - natural cubic spline + // Extrapolation - Cauchy equation + public static double polymethacrylate(double wavelength){ + return RefractiveIndex.polymethacrylate(wavelength); + } + + // Returns the real refractive index of AIR for a given wavelength (in metres) + // Interpolation - uses the Cauchy equation (see Born & Wolf section 2.3) + // Extrapolation - uses the Cauchy equation - may be invalid and will be invalid within an absorption band + public static double air(double wavelength){ + return RefractiveIndex.air(wavelength); + } + + // Returns the real refractive index of WATER + // for a given wavelength (in metres)and a given temperature (Celsius) + // Interpolation - natural bicubic spline + public static double water(double wavelength, double temperature){ + return RefractiveIndex.water(wavelength, temperature); + } + + // Returns the refractive index of pva solutions as a function of g/l pva concentration + // Data Poly(vinyl alcohol): basic properties and uses by J G Pritchard (1970) + // pva refractive index increment fitted to modified Cauchy equation: + // dn = 1 + a1*(1 + b1/(lambda*lambda)) + // concn g/l concentration of pva + // temp temperature (degree Celsius) (t = 30C for original pva increment calculation) + // wavl wavelength in metres + public static double pva(double concn, double wavl, double temp){ + return RefractiveIndex.pva(concn, wavl, temp); + } + + // Returns the refractive index of a NaCl solution for a given wavelength (in metres), + // a given temperature (degrees Celcius) and a given NaCl concentration (M) + // Interpolation - bicubic spline + public static double saline(double concentration, double wavelength, double temperature){ + return RefractiveIndex.saline(concentration, wavelength, temperature); + } + + // Returns the refractive index of sucrose solutions as a function of g/l sucrose concentration + // Wavelength - sodium D line 589.3 nm + // Interpolation - natural cubic spline + // Extrapolation above 1208.2g/l Lorenz-lorenz equation based on + // average refraction of sucrose calculated from experimental data + // Data - Rubber Handbook + public static double sucrose(double concentration, double temperature){ + return RefractiveIndex.water(concentration, temperature); + } + + // Returns the refractive index of a mixture of material A and material B, + // using the Lorenz-Lorentz equation, given the refractive index of A (na), of B (nb), + // the molecular wight of A (molwta), of B (molwtb), the mole fraction of A (molfracta), + // and the density of A (densa), of B (densb) and of the mixture (densab). + public static double lorenzLorentz(double na, double nb, double molwta, double molwtb, double molfracta, double densa, double densb, double densab){ + return RefractiveIndex.lorenzLorentz(na, nb, molwta, molwtb, molfracta, densa, densb, densab); + } + + + // Returns the refractive index of a mixture of n materials, + // using the Lorenz-Lorentz equation, given an array of the refractive indices (ni), + // an array of the molecular wights (molwt), an array the mole fractions (molfract), + // and an array of the densities (dens) and the density of the mixture (densmix). + public static double lorenzLorentz(double[] ni, double[] molwt, double[] molfract, double[] dens, double densmix){ + return RefractiveIndex.lorenzLorentz(ni, molwt, molfract, dens, densmix); + } + +} + diff --git a/src/main/java/flanagan/physprop/Saline.java b/src/main/java/flanagan/physprop/Saline.java new file mode 100755 index 0000000000000000000000000000000000000000..9c700ed534c1714426073daf2c0e5858704e649b --- /dev/null +++ b/src/main/java/flanagan/physprop/Saline.java @@ -0,0 +1,120 @@ +/* +* Saline Class +* +* Methods for returning the physical properties of +* aqueous sodium chloride solutions: +* viscosity, density, refractive index +* mole fraction and molecular weight. +* Methods for interconverting molar - grams per litre. +* +* Author: Dr Michael Thomas Flanagan. +* +* Created: July 2003 +* Updated: 1 July 2003 and 5 May 2004 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Saline.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) May 2004 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.physprop; +import flanagan.interpolation.CubicSpline; + +public class Saline{ + + public static final double MOLWEIGHT = 58.45; // NaCl molecular weight + + // METHODS + // Returns the viscosity (Pa s) of saline at a given Molar NaCl concentration and + // at a given temperature (Celsius) + // Interpolation - natural cubic spline plus activation energy scaling + // Data - Rubber Handbook + public static double viscosity(double concentration, double temperature){ + + double[] conc = {0, 0.017, 0.034, 0.051, 0.069, 0.086, 0.103, 0.12, 0.137, 0.155, 0.172, 0.189, 0.207, 0.224, 0.241, 0.259, 0.276, 0.294, 0.311, 0.329, 0.346, 0.364, 0.382, 0.399, 0.418, 0.435, 0.452, 0.47, 0.488, 0.505, 0.523, 0.541, 0.559, 0.577, 0.595, 0.653, 0.631, 0.649, 0.667, 0.685, 0.703, 0.721, 0.739, 0.757, 0.775, 0.794, 0.812, 0.83, 0.848, 0.866, 0.885, 0.921, 0.958, 0.995, 1.032, 1.069, 1.106, 1.144, 1.181, 1.218, 1.256, 1.294, 1.331, 1.369, 1.407, 1.445, 1.484, 1.522, 1.56, 1.599, 1.637, 1.676, 1.715, 1.754, 1.193, 1.832, 1.93, 2.029, 2.129, 2.229, 2.33, 2.432, 2.534, 2.637, 2.741, 2.845, 3.056, 3.27, 3.486, 3.706, 3.928, 4.153, 4.382, 4.613, 4.848, 5.085, 5.326}; + double[] visc = {0.00100219, 0.00100389, 0.0010057, 0.0010074, 0.00100911, 0.00101082, 0.00101353, 0.00101524, 0.00101695, 0.00101866, 0.00102038, 0.0010221, 0.00102392, 0.00102463, 0.00102635, 0.00102807, 0.00102979, 0.00103152, 0.00103324, 0.00103396, 0.00103579, 0.00103752, 0.00103925, 0.00104098, 0.00104271, 0.00104445, 0.00104527, 0.00104701, 0.00104875, 0.00105049, 0.00105223, 0.00105397, 0.0010548, 0.00105654, 0.00105829, 0.00106004, 0.00106178, 0.00106251, 0.00106437, 0.00106653, 0.00106787, 0.00106963, 0.00107138, 0.00107325, 0.00107501, 0.00107677, 0.00107853, 0.00107926, 0.00108113, 0.0010829, 0.00108467, 0.00108935, 0.00109289, 0.00109655, 0.00110011, 0.00110378, 0.00110735, 0.00111207, 0.00111566, 0.00111935, 0.0011241, 0.0011277, 0.00113247, 0.00113619, 0.00114086, 0.0011446, 0.00114939, 0.00115409, 0.00115891, 0.00116373, 0.00116857, 0.0011733, 0.00117815, 0.00118301, 0.00118788, 0.00119383, 0.00120655, 0.00122041, 0.00123553, 0.00125073, 0.00126588, 0.00128232, 0.00129885, 0.00131656, 0.00133337, 0.00135126, 0.00138744, 0.00142411, 0.00146355, 0.00150682, 0.00155756, 0.0016135, 0.00167732, 0.00174526, 0.00182018, 0.00190192, 0.00198975}; + double[] deriv = {0, 0.000768695, -0.000791042, 0.000111737, -0.00135411, 0.00742974, -0.0076036, 0.0022234, -0.00129002, 0.00105411, -0.000794614, 0.00212435, -0.00753267, 0.00782177, -0.00278555, 0.00157181, -0.00153892, 0.00281175, -0.00816056, 0.00868783, -0.0032574, 0.000617161, 0.000788751, -0.00190588, 0.00313379, -0.00715407, 0.00638216, -0.00191908, 0.00129416, -0.00129001, 0.00189902, -0.00630606, 0.00647338, -0.0027356, 0.0046542, -0.0182844, -0.0177707, 0.00963645, 0.000150791, -0.00468406, 0.00340026, -0.0011392, 0.000971365, -0.000524035, -0.000912263, 0.00242436, -0.00728848, 0.00765548, -0.00222235, -0.000617948, 0.00287778, -0.00232672, 0.000815016, -0.000407408, 0.000376341, -0.000615852, 0.00164879, -0.00153126, 0.000106328, 0.00154422, -0.00220911, 0.00251382, -0.00237932, 0.00204582, -0.00185658, 0.00151625, -0.00042451, 0.000300603, -0.000279286, 0.000309564, -0.00037128, 0.000228089, -6.77046e-005, 8.21768e-005, 0.00126799, -6.84692e-005, 0.000138594, 0.000134632, -1.04198e-006, -8.24638e-005, 0.000210442, -9.85469e-005, 0.000235649, -0.000264725, 0.000225783, -3.92966e-005, -9.59633e-006, 7.36642e-005, 2.83662e-005, 0.000199494, 3.90432e-005, 0.000183066, 2.35719e-005, 0.000125227, 0.000110721, 9.52208e-005, 0}; + double viscWaterT, viscWater20, viscosity; + int n = conc.length; + + // Calculate viscosity at 20 C + if(concentration>=conc[0] && concentration<=conc[n-1]){ + viscosity=CubicSpline.interpolate(concentration, conc, visc, deriv); + } + else{ + throw new IllegalArgumentException("concentration outside the experimental data limits"); + } + + if(temperature!=20.0){ + // Scale temperature dependence to that of water, + // i.e. assume same activation energy + viscWater20 = Water.viscosity(20.0); + viscWaterT = Water.viscosity(temperature); + viscosity=viscosity*viscWaterT/viscWater20; + } + return viscosity; + } + + // Returns the density (kg/m^3) of NaCl solutions as a function of M NaCl concentration + // Interpolation - natural cubic spline + // Data - Rubber Handbook + // Temp = 20C + public static double density(double concentration){ + + double[] conc = {0, 0.017, 0.034, 0.051, 0.069, 0.086, 0.103, 0.12, 0.137, 0.155, 0.172, 0.189, 0.207, 0.224, 0.241, 0.259, 0.276, 0.294, 0.311, 0.329, 0.346, 0.364, 0.382, 0.399, 0.418, 0.435, 0.452, 0.47, 0.488, 0.505, 0.523, 0.541, 0.559, 0.577, 0.595, 0.653, 0.631, 0.649, 0.667, 0.685, 0.703, 0.721, 0.739, 0.757, 0.775, 0.794, 0.812, 0.83, 0.848, 0.866, 0.885, 0.921, 0.958, 0.995, 1.032, 1.069, 1.106, 1.144, 1.181, 1.218, 1.256, 1.294, 1.331, 1.369, 1.407, 1.445, 1.484, 1.522, 1.56, 1.599, 1.637, 1.676, 1.715, 1.754, 1.193, 1.832, 1.93, 2.029, 2.129, 2.229, 2.33, 2.432, 2.534, 2.637, 2.741, 2.845, 3.056, 3.27, 3.486, 3.706, 3.928, 4.153, 4.382, 4.613, 4.848, 5.085, 5.326}; + double[] dens = {998.2, 998.9, 999.7, 1000.4, 1001.1, 1001.8, 1002.5, 1003.2, 1003.9, 1004.6, 1005.3, 1006, 1006.8, 1007.5, 1008.2, 1008.9, 1009.6, 1010.3, 1011, 1011.7, 1012.5, 1013.2, 1013.9, 1014.6, 1015.3, 1016, 1016.8, 1017.5, 1018.2, 1018.9, 1019.6, 1020.3, 1021.1, 1021.8, 1022.5, 1023.2, 1023.9, 1024.6, 1025.4, 1026.5, 1026.8, 1027.5, 1028.2, 1029, 1029.7, 1030.4, 1031.1, 1031.8, 1032.6, 1033.3, 1034, 1035.5, 1036.9, 1038.4, 1039.8, 1041.3, 1042.7, 1044.2, 1045.6, 1047.1, 1048.6, 1050, 1051.5, 1053, 1054.4, 1055.9, 1057.4, 1058.8, 1060.3, 1061.8, 1063.3, 1064.7, 1066.2, 1067.7, 1069.2, 1070.7, 1074.4, 1078.1, 1081.9, 1085.7, 1089.4, 1093.2, 1097, 1100.8, 1104.7, 1108.5, 1116.2, 1124, 1131.9, 1139.8, 1147.8, 1155.8, 1164, 1172.1, 1180.4, 1188.7, 1197.2}; + double[] deriv = {0, 685.75, -666.876, -94.3722, 234.303, -57.4711, -4.41831, 75.1444, -296.159, 318.233, -189.411, 439.409, -440.601, 195.58, -341.719, 381.664, -402.356, 441.731, -585.487, 1097.17, -1014.34, 185.143, 273.774, -515.957, 341.504, 660.063, -905.631, 175.193, 204.858, -221.651, -94.0302, 597.771, -445.203, -668.811, 3120.45, -10744.6, -14968.4, 3784.07, 1683.98, -4964.43, 3358.94, -1063.92, 896.753, -671.238, -63.6541, 237.473, -226.825, 669.828, -600.633, -119.146, 386.711, -314.64, 244.402, -224.691, 216.087, -201.381, 151.163, -142.321, 156.457, -45.2313, -142.246, 198.704, -59.7198, -126.19, 148.967, -54.1662, -86.975, 152.369, -106.99, 118.297, -209.797, 162.973, -47.6169, 27.4948, 385.473, -22.8199, -2.39438, 9.00548, 4.10437, -25.4229, 15.9561, -1.79451, -8.77808, 15.6492, -18.5946, 3.25592, -1.85219, 2.90469, -6.24447, 3.76304, -5.36519, 4.79201, -7.11856, 4.3037, -3.58034, 2.44792, 0}; + double density; + int n = conc.length; + + if(concentration>=conc[0] && concentration<=conc[n-1]){ + density=CubicSpline.interpolate(concentration, conc, dens, deriv); + } + else{ + throw new IllegalArgumentException("concentration outside the experimental data limits"); + } + return density; + } + + // Returns the refractive index of a NaCl solution for a given wavelength (in metres), + // a given temperature (degrees Celcius) and a given NaCl concentration (M) + // Interpolation - natural bicubic spline + // Uses method in class RefrIndex + // Data - Rubber Handbook + public static double refractIndex(double concentration, double wavelength, double temperature){ + return RefrIndex.saline(concentration, wavelength, temperature); + } + + // Returns the mole fraction at 20 C of NaCl in an aqueous NaCl solution for a given NaCl concentration (M) + public static double moleFraction(double concentration){ + double molesNacl, totalWeight, molesWater; + molesNacl=concentration*1000; + totalWeight=Saline.density(concentration)*1000.0; + molesWater=(totalWeight-molesNacl*Saline.MOLWEIGHT)/Water.MOLWEIGHT; + return molesNacl/(molesWater + molesNacl); + } + + // Converts Molar NaCl to g/l NaCl + public static double molarToGperl(double molar){ + return molar*Saline.MOLWEIGHT; + } + + // Converts g/l NaCl to Molar NaCl + public static double gperlToMolar(double gperl){ + return gperl/Saline.MOLWEIGHT; + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/physprop/Sucrose.java b/src/main/java/flanagan/physprop/Sucrose.java new file mode 100755 index 0000000000000000000000000000000000000000..a5cfa71347d46d35a3627c5e4aa1ab2c863d2da7 --- /dev/null +++ b/src/main/java/flanagan/physprop/Sucrose.java @@ -0,0 +1,377 @@ +/* +* Sucrose Class +* +* Methods for returning the physical properties of +* aqueous sucrose solutions: +* viscosity, density, refractive index, solubility, specific volume, +* diffusion coefficient, mole fraction and molecular weight. +* Methods for interconverting molar - grams per litre - percent weight by weight. +* +* Author: Dr Michael Thomas Flanagan. +* +* Created: July 2003 +* Updated: 1 July 2003, May 2004, 29-31 July 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Sucrose.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2008 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.physprop; + +import flanagan.math.Fmath; +import flanagan.math.ArrayMaths; +import flanagan.interpolation.CubicSpline; +import flanagan.interpolation.BiCubicSpline; + +public class Sucrose{ + + public static final double MOLWEIGHT = 342.3; // Sucrose molecular weight + + // METHODS + + // Returns the viscosity (Pa s) of sucrose solutions as a function of + // the g/l sucrose concentration and temperature. + // Interpolation - natural cubic spline and bicubic spline - log of the viscosity + // Data - Rubber Handbook + public static double viscosity(double gPerL, double temperature){ + + + if(temperature<0.0)throw new IllegalArgumentException("Temperature, " + temperature + ", out of range"); + if(gPerL<0.0)throw new IllegalArgumentException("Concentration, " + gPerL + " g/l, out of range"); + + double[] visc20 = {1.000, 1.013, 1.026, 1.039, 1.053, 1.067, 1.082, 1.097, 1.112, 1.128, 1.144, 1.160, 1.177, 1.195, 1.213, 1.232, 1.251, 1.271, 1.291, 1.312, 1.333, 1.378, 1.426, 1.477, 1.531, 1.589, 1.650, 1.716, 1.786, 1.861, 1.941, 2.120, 2.326, 2.568, 2.849, 3.181, 3.754, 4.044, 4.612, 5.304, 6.150, 7.220, 8.579, 10.28, 12.49, 15.40, 19.30, 24.63, 32.06, 42.69, 58.37, 82.26, 119.9, 181.7, 287.9, 480.6, 853.2, 1628}; + int viscLength = visc20.length; + for(int i=0; i<viscLength; i++)visc20[i] *= 1.005; + double[] concnWA = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 8.5, 9, 9.5, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84}; + double[] concnGA = {0, 5, 10, 15.1, 20.1, 25.2, 30.3, 35.4, 40.6, 45.7, 50.9, 56.1, 61.3, 66.5, 71.8, 77.1, 82.4, 87.7, 93.1, 98.4, 103.8, 114.7, 125.6, 136.6, 147.7, 158.9, 170.2, 181.5, 193, 204.5, 216.2, 239.8, 263.8, 288.1, 312.9, 338.1, 363.7, 389.8, 416.2, 443.2, 470.6, 498.4, 526.8, 555.6, 584.9, 614.8, 645.1, 676, 707.4, 739.3, 771.9, 804.9, 838.6, 872.8, 907.6, 943.1, 979.1, 1015.7, 1053, 1090.9, 1129.4, 1168.5, 1208.2}; + ArrayMaths amC = new ArrayMaths(concnGA); + double[] zero = {1.7921, 1.5188, 1.3077, 1.1404, 1.0050, 0.8937, 0.8007, 0.7225, 0.6560, 0.5988, 0.5454, 0.5064, 0.4688, 0.4355, 0.4061, 0.3799, 0.3565, 0.3355, 0.3165, 0.2994, 0.2838}; + int length0 = zero.length; + + double[] twenty = {3.804, 3.154, 2.652, 2.267, 1.960, 1.704, 1.504, 1.331, 1.193, 1.070, 0.970, 0.884, 0.808, 0.742, 0.685, 0.635, 0.590, 0.550}; + int length20 = twenty.length; + double[] forty = {14.77, 11.56, 9.794, 7.468, 6.200, 5.187, 4.382, 3.762, 3.249, 2.847, 2.497, 2.219, 1.982, 1.778, 1.608, 1.462, 1.334, 1.221, 1.123, 1.037, 0.960}; + int length40 = forty.length; + double[] sixty = {238, 156, 109.8, 74.6, 56.5, 43.86, 33.78, 26.52, 21.28, 17.18, 14.01, 11.67, 9.83, 8.34, 7.15, 6.20, 5.40, 4.73, 4.15, 3.72, 3.34}; + int length60 = sixty.length; + double[] temp = new double[length0]; + temp[0] = 0; + for(int i=1; i<length60; i++)temp[i] = temp[i-1] + 5.0; + ArrayMaths am0 = new ArrayMaths(zero); + ArrayMaths am20 = new ArrayMaths(twenty); + ArrayMaths am40 = new ArrayMaths(forty); + ArrayMaths am60 = new ArrayMaths(sixty); + ArrayMaths amT = new ArrayMaths(temp); + + double[] concn85 = {0.0, 216.2, 470.6, 771.9}; + double[] concn100 = {0.0, 470.6, 771.9}; + + double ret = Double.NaN; + + if(gPerL<=771.9){ + if(temperature<=85){ + + int lengthT85 = length20; + int lengthC85 = amC.indexOf(771.9); + double[] temp85 = amT.subarray_as_double(0, length20-1); + double[] conc85 = amC.subarray_as_double(0, lengthC85); + + lengthC85++; + double[][] array = new double[lengthT85][lengthC85]; + for(int i=0; i<lengthT85; i++){ + double[] lvisc = {Math.log(zero[i]), Math.log(twenty[i]), Math.log(forty[i]), Math.log(sixty[i])}; + CubicSpline cs = new CubicSpline(concn85, lvisc); + for(int j=0; j<lengthC85; j++){ + array[i][j] = cs.interpolate(conc85[j]); + } + } + BiCubicSpline bcs = new BiCubicSpline(temp85, conc85, array); + ret = Math.exp(bcs.interpolate(temperature, gPerL)); + } + else{ + if(temperature>100.0){ + throw new IllegalArgumentException("Temperature, " + temperature + ", out of range"); + } + else{ + int lengthT100 = length60; + int lengthC100 = amC.indexOf(771.9); + double[] temp100 = amT.subarray_as_double(0, lengthT100-1); + double[] conc100 = amC.subarray_as_double(0, lengthC100); + lengthC100++; + + double[][] array = new double[lengthT100][lengthC100]; + for(int i=0; i<lengthT100; i++){ + double[] lvisc = {Math.log(zero[i]), Math.log(forty[i]), Math.log(sixty[i])}; + CubicSpline cs = new CubicSpline(concn100, lvisc); + for(int j=0; j<lengthC100; j++){ + array[i][j] = cs.interpolate(conc100[j]); + + } + } + BiCubicSpline bcs = new BiCubicSpline(temp100, conc100, array); + ret = Math.exp(bcs.interpolate(temperature, gPerL)); + } + } + } + else{ + if(temperature==20 && gPerL<=1208.2){ + double[] concM = amC.subarray_as_double(0, viscLength-1); + CubicSpline cs = new CubicSpline(concM, visc20); + ret = cs.interpolate(gPerL); + } + else{ + throw new IllegalArgumentException("Concentration, " + gPerL + " g/l, for this temperature, " + temperature + " C,is out of range"); + } + } + + return ret; + } + + + // Returns the refractive index of sucrose solutions as a function of g/l sucrose concentration + // Wavelength - sodium D line 589.3 nm + // Interpolation - natural cubic spline + // Extrapolation above 1208.2g/l Lorenz-lorenz equation based on + // average refraction of sucrose calculated from experimental data + // Data - Rubber Handbook + // Uses method in class RefrIndex + public static double refractIndex(double concentration, double temperature){ + return RefrIndex.sucrose(concentration, temperature); + } + + // Returns the solubility of sucrose in water as g/l solution as a function of temperature + // Data - Rubber handbook + // interpolation - cubic spline + public static double solubility(double temperature){ + + double[] tempc = {0.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0, 70.0, 75.0, 80.0, 85.0, 90.0, 95.0, 100.0}; + double[] solub = {64.18, 64.87, 65.58, 66.53, 67.09, 67.89, 68.8, 69.55, 70.42, 71.32, 72.25, 73.2, 74.18, 75.88, 76.22, 77.27, 78.36, 79.46, 80.61, 81.77, 82.97}; + double[] deriv = {0, -0.00489357, 0.0243743, -0.0350036, 0.0220399, 0.00444386, -0.0134154, 0.0108176, -0.00105492, 0.000602123, 0.00584643, -0.0191879, 0.078105, -0.120432, 0.0772233, -0.0180611, 0.00462116, 0.00197648, -0.00052706, 0.00253177, 0}; + + double solubility; + + int n=tempc.length; + + if(temperature>=tempc[0] && temperature<=tempc[n-1]){ + solubility = CubicSpline.interpolate(temperature, tempc, solub, deriv); + } + else{ + throw new IllegalArgumentException("The temperatue is outside the experimental data limits"); + } + solubility=weightpercentToGperl(solubility, temperature); + + return solubility; + } + + // Returns the density (kg/m^3) of sucrose solutions as a function of g/l sucrose concentration + // Interpolation - natural cubic spline + // Data - Rubber Handbook + // concentration g/l concentration of sucrose for which the density is required + // temperature temperature (degree Celsius) + public static double density(double concentration, double temperature){ + + double[] concnG = {0, 5, 10, 15.1, 20.1, 25.2, 30.3, 35.4, 40.6, 45.7, 50.9, 56.1, 61.3, 66.5, 71.8, 77.1, 82.4, 87.7, 93.1, 98.4, 103.8, 114.7, 125.6, 136.6, 147.7, 158.9, 170.2, 181.5, 193, 204.5, 216.2, 239.8, 263.8, 288.1, 312.9, 338.1, 363.7, 389.8, 416.2, 443.2, 470.6, 498.4, 526.8, 555.6, 584.9, 614.8, 645.1, 676, 707.4, 739.3, 771.9, 804.9, 838.6, 872.8, 907.6, 943.1, 979.1, 1015.7, 1053, 1090.9, 1129.4, 1168.5, 1208.2}; + double[] dens = {998.2, 1000.2, 1002.1, 1004, 1006, 1007.9, 1009.9, 1011.9, 1013.9, 1015.8, 1017.8, 1019.8, 1021.8, 1023.8, 1025.9, 1027.9, 1029.9, 1032, 1034, 1036.1, 1038.1, 1042.3, 1046.5, 1050.7, 1054.9, 1059.2, 1063.5, 1067.8, 1072.2, 1076.6, 1081, 1089.9, 1099, 1108.2, 1117.5, 1127, 1136.6, 1146.4, 1156.2, 1166.3, 1176.5, 1186.8, 1197.2, 1207.9, 1218.6, 1229.5, 1240.6, 1251.8, 1263.2, 1274.7, 1286.4, 1298.3, 1310.3, 1322.4, 1334.8, 1347.2, 1359.9, 1372.6, 1385.5, 1398.6, 1411.7, 1425, 1438.3}; + double[] deriv = {0, -0.00495764, -0.00416945, 0.0126089, -0.0137458, 0.00978735, -0.00233552, -0.000445268, -0.00464715, 0.00502912, -0.00144255, 0.000741061, -0.0015217, 0.00534573, -0.00654364, -0.0005311, 0.00866803, -0.0127811, 0.0134147, -0.0118716, 0.00515152, -0.0012962, 3.32699e-005, -0.000758744, 0.00112898, -0.000770477, 0.000145246, 0.000189494, 0.000189925, -0.000949193, 0.000223635, 6.85836e-005, 2.005e-005, -0.000287156, 0.000246234, -0.000222108, 0.000174076, -0.000361684, 0.000296689, -0.000183935, 4.13755e-005, -0.000362702, 0.000485174, -0.000459014, 4.51875e-005, 0.000142595, -0.00025712, 0.000125835, -0.000132083, -8.03786e-005, 0.000151752, -0.000212951, -0.000110921, 0.00024994, -0.000447536, 0.00033998, -0.00032882, 2.20206e-005, 5.04017e-005, -0.000253039, 0.000115168, -0.000224291, 0,}; + double[] concfit = {0, 200, 400, 600, 800, 1000, 1200}; + double[] coeff0 = {0.000998363, 0.000926078, 0.000864741, 0.000812717, 0.000766724, 0.000727182, 0.000692587}; + double[] deriv0 = {0, 3.53118e-010, 2.29729e-010, 1.24915e-010, 1.75259e-010, 1.41698e-010, 0}; + double[] coeff1 = {2.42825e-007, 2.60851e-007, 2.61522e-007, 1.52504e-007, 2.35274e-007, 2.1465e-007, 1.91079e-007}; + double[] deriv1 = {0, 1.11593e-012, -7.06697e-012, 1.06986e-011, -6.95925e-012, 1.6293e-012, 0}; + double density, coefficient0, coefficient1; + int n=concfit.length; + if(concentration>=concfit[0] && concentration<=concfit[n-1] && temperature>=0 && temperature<=50){ + coefficient0 = CubicSpline.interpolate(concentration, concfit, coeff0, deriv0); + coefficient1 = CubicSpline.interpolate(concentration, concfit, coeff1, deriv1); + + density=1.0/(coefficient0+coefficient1*temperature); + } + else{ + throw new IllegalArgumentException("Either Temperature or Concentration is outside the experimental data limits"); + } + return density; + } + + // Returns the specific volume (m^3/kg) of sucrose in aqueous solution at 20 C + // as a function of g/l sucrose concentration + // Average value = 0.000621903 sd = 6.16153e-006 This value is used outside the + // limits of the experimental concentration and temperature data + // Interpolation - natural cubic spline + // Data - calculated from density of water and displaced water volume in the Rubber Handbook + public static double specificVolume(double concentration){ + + double[] concnG = {0, 5, 10, 15.1, 20.1, 25.2, 30.3, 35.4, 40.6, 45.7, 50.9, 56.1, 61.3, 66.5, 71.8, 77.1, 82.4, 87.7, 93.1, 98.4, 103.8, 114.7, 125.6, 136.6, 147.7, 158.9, 170.2, 181.5, 193, 204.5, 216.2, 239.8, 263.8, 288.1, 312.9, 338.1, 363.7, 389.8, 416.2, 443.2, 470.6, 498.4, 526.8, 555.6, 584.9, 614.8, 645.1, 676, 707.4, 739.3, 771.9, 804.9, 838.6, 872.8, 907.6, 943.1, 979.1, 1015.7, 1053, 1090.9, 1129.4, 1168.5, 1208.2}; + double[] specv = {0.000621118, 0.000621118, 0.000621118, 0.000617005, 0.000618028, 0.000616189, 0.000614968, 0.00061693, 0.000614406, 0.000615988, 0.00061604, 0.000616082, 0.000616117, 0.000616147, 0.000616709, 0.000615895, 0.000616401, 0.000616846, 0.000616577, 0.000616964, 0.000616717, 0.000616629, 0.000617353, 0.00061751, 0.000617225, 0.000617222, 0.000617445, 0.000618193, 0.000618211, 0.000618228, 0.000618597, 0.000618712, 0.000619007, 0.000619651, 0.000619844, 0.000620164, 0.000620584, 0.000620923, 0.000621494, 0.000621832, 0.000622455, 0.000622911, 0.00062337, 0.000623873, 0.000624478, 0.000624905, 0.00062537, 0.000625979, 0.000626516, 0.000627126, 0.000627766, 0.000628414, 0.000628964, 0.000629685, 0.000630377, 0.00063108, 0.000631819, 0.000632624, 0.000633334, 0.000634105, 0.000635019, 0.00063589, 0.000636886}; + double[] deriv = {0, 9.54239e-008, -3.81696e-007, 4.69472e-007, -2.94053e-007, 3.9486e-008, 2.78669e-007, -4.19907e-007, 3.86217e-007, -1.95897e-007, 5.08841e-008, -9.858e-009, -1.30053e-008, 6.07699e-008, -1.14515e-007, 1.03377e-007, -1.70413e-008, -4.82412e-008, 5.92625e-008, -5.10779e-008, 1.22998e-008, 9.25257e-009, -8.30337e-009, -4.55102e-009, 4.7569e-009, -8.20925e-010, 9.1751e-009, -1.12103e-008, 1.71621e-009, 4.30015e-009, -3.32497e-009, 1.03549e-009, 1.01682e-009, -1.55614e-009, 6.3652e-010, 1.76082e-010, -4.56375e-010, 8.49619e-010, -9.64276e-010, 9.59006e-010, -6.2015e-010, 1.50421e-010, -3.91772e-011, 2.78811e-010, -4.15371e-010, 9.3832e-011, 2.48046e-010, -2.27533e-010, 1.60667e-010, -3.36646e-011, 6.9795e-011, -2.4342e-010, 3.04857e-010, -1.35319e-010, 3.06608e-011, -2.68355e-012, 1.01252e-010, -1.58595e-010, 5.29862e-011, 1.52913e-010, -1.29603e-010, 1.39208e-010, 0}; + double specvol, average=0.000621903; + int n=concnG.length; + + if(concentration>=concnG[0] && concentration<=concnG[n-1]){ + specvol = CubicSpline.interpolate(concentration, concnG, specv, deriv); + } + else{ + specvol=average; + } + return specvol; + } + + + // Returns the diffusion coefficient (m^2 s^-1) of sucrose in aqueous solution + // as a function of the g/l sucrose concentration + // concentration g/l concentration of sucrose for which a diffusion coefficient is required + // temperature temperature in degree Celsius + + public static double diffCoeff(double concentration, double temperature){ + + double diffcoef, f, viscosity, specvol, vol, radius, tempa; + + tempa=temperature - Fmath.T_ABS; + + viscosity=Sucrose.viscosity(concentration, temperature); + specvol=Sucrose.specificVolume(concentration); + vol=Sucrose.MOLWEIGHT*specvol/(Fmath.N_AVAGADRO*1000); + radius=Math.pow(3.0*vol/(4.0*Math.PI),1.0/3.0); + + f=6.0*Math.PI*viscosity*radius; + + diffcoef=Fmath.K_BOLTZMANN*tempa/f; + + return diffcoef; + } + + // Returns the mole fraction of sucrose in an aqueous sucrose solution + // for a given sucrose concentration (g/l) and temperature + public static double moleFraction(double concentration, double temperature){ + double weightSucrose, totalWeight, molesWater, molesSucrose; + weightSucrose=concentration*1000; + molesSucrose=weightSucrose/Sucrose.MOLWEIGHT; + totalWeight=Sucrose.density(concentration, temperature)*1000.0; + molesWater=(totalWeight-weightSucrose)/Water.MOLWEIGHT; + return molesSucrose/(molesWater + molesSucrose); + } + + // Converts Molar sucrose to g/l sucrose + public static double molarToGperl(double molar){ + return molar*Sucrose.MOLWEIGHT; + } + + // Converts Molar sucrose to weight per cent sucrose + public static double molarToWeightpercent(double molar, double temperature){ + double weight; + weight = Sucrose.molarToGperl(molar); + weight = Sucrose.gperlToWeightpercent(weight, temperature); + return weight; + } + + // Converts g/l sucrose to Molar sucrose + public static double gperlToMolar(double gperl){ + return gperl/Sucrose.MOLWEIGHT; + } + + // Converts a g/l aqueous sucrose concentration to the % weight concentration + // (g sucrose / 100g solution)at a gven temperature (Celsius) + // Interpolation - cubic spline (20C) and calculation from density + // Data - Rubber Handbook + public static double gperlToWeightpercent(double concentration, double temperature){ + + double[] concnG = {0, 5, 10, 15.1, 20.1, 25.2, 30.3, 35.4, 40.6, 45.7, 50.9, 56.1, 61.3, 66.5, 71.8, 77.1, 82.4, 87.7, 93.1, 98.4, 103.8, 114.7, 125.6, 136.6, 147.7, 158.9, 170.2, 181.5, 193, 204.5, 216.2, 239.8, 263.8, 288.1, 312.9, 338.1, 363.7, 389.8, 416.2, 443.2, 470.6, 498.4, 526.8, 555.6, 584.9, 614.8, 645.1, 676, 707.4, 739.3, 771.9, 804.9, 838.6, 872.8, 907.6, 943.1, 979.1, 1015.7, 1053, 1090.9, 1129.4, 1168.5, 1208.2}; + double[] concnW = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 8.5, 9, 9.5, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84}; + double[] deriv = {0, 0.000224325, -0.0008973, 0.00102728, -0.000882025, 0.00017957, 0.000163747, -0.000834558, 0.000970111, -0.000849482, 0.000238375, -0.000104019, 0.000177701, -0.000606786, 0.000176058, -9.74476e-005, 0.000213732, -0.00075748, 0.000850948, -0.000686359, -5.6318e-005, 4.08684e-005, -0.000107156, -6.87474e-005, -6.27622e-005, -0.000112854, 9.20828e-005, -0.000255477, 0.000119556, -0.000222749, 3.59124e-006, -8.44627e-005, -2.16033e-005, -8.47265e-005, -4.4802e-005, -4.36141e-005, -7.34483e-005, -1.02994e-005, -8.43266e-005, -3.04826e-005, -3.26613e-005, -6.69242e-005, -2.42674e-005, -4.13785e-005, -5.47191e-005, -1.76386e-005, -5.07722e-005, -3.04569e-005, -2.61186e-005, -5.41411e-005, -7.97549e-006, -5.00124e-005, -1.83509e-005, -3.00707e-005, -3.65588e-005, -1.72617e-005, -2.57937e-005, -2.9995e-005, -2.0797e-005, -2.23338e-005, -1.90539e-005, -2.47041e-005, 0}; + double weight; + + weight=concentration*0.1/(Sucrose.density(concentration, temperature)/1000); + + return weight; + } + + // Converts weight percent sucrose to Molar sucrose + public static double weightpercentToMolar(double weight, double temperature){ + double molar; + molar = weightpercentToGperl(weight, temperature); + molar = gperlToMolar(molar); + return molar; + } + + // Converts the % weight concentration (g sucrose / 100g solution) + // to a g/l aqueous sucrose concentration + // interpolation - natural cubic spline (20C) and calculation + // Data - Rubber Handbook + // concentration % weight concentration of sucrose + // temperature temperature (degrees Celsius) + public static double weightpercentToGperl(double concentration, double temperature){ + double[] concnW = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 8.5, 9, 9.5, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84}; + double[] concnG = {0, 5, 10, 15.1, 20.1, 25.2, 30.3, 35.4, 40.6, 45.7, 50.9, 56.1, 61.3, 66.5, 71.8, 77.1, 82.4, 87.7, 93.1, 98.4, 103.8, 114.7, 125.6, 136.6, 147.7, 158.9, 170.2, 181.5, 193, 204.5, 216.2, 239.8, 263.8, 288.1, 312.9, 338.1, 363.7, 389.8, 416.2, 443.2, 470.6, 498.4, 526.8, 555.6, 584.9, 614.8, 645.1, 676, 707.4, 739.3, 771.9, 804.9, 838.6, 872.8, 907.6, 943.1, 979.1, 1015.7, 1053, 1090.9, 1129.4, 1168.5, 1208.2}; + double[] deriv = {0, -0.230536, 0.922143, -1.05804, 0.909999, -0.181959, -0.182163, 0.910611, -1.06028, 0.930517, -0.261788, 0.116633, -0.204746, 0.702351, -0.204657, 0.116276, -0.260447, 0.925512, -1.0416, 0.840888, 0.078047, -0.0545852, 0.140294, 0.0934103, 0.0860649, 0.16233, -0.135385, 0.37921, -0.181457, 0.346616, -0.00500719, 0.141714, 0.0381529, 0.155675, 0.0891471, 0.0877366, 0.159906, 0.0226375, 0.199544, 0.0791879, 0.0837046, 0.185994, 0.0723209, 0.124723, 0.178788, 0.0601258, 0.180709, 0.117039, 0.101137, 0.228414, 0.0352078, 0.230755, 0.0917725, 0.152155, 0.199608, 0.0994148, 0.152733, 0.189652, 0.138658, 0.155717, 0.138476, 0.190381, 0}; + double gperl=0.0, f1, f2, f3, g1, g2, g3, tol; + int n=concnW.length, j=-1, itermax=1000; + boolean test=true; + + if(concentration<concnW[0] || concentration>concnW[n-1]){ + throw new IllegalArgumentException("concentration is outside the experimental data limits"); + } + + // obtains g/l by bisection using g/l=weight%*density + tol=concentration*1e-4; + g1=0.0; + g2=1200; + f1=g1-concentration*Sucrose.density(g1,temperature)/100; + f2=g2-concentration*Sucrose.density(g2,temperature)/100; + if ((f1 > 0.0 && f2 > 0.0) || (f1 < 0.0 && f2 < 0.0)){ + throw new IllegalArgumentException("Root must be bracketed in the bisection"); + } + test=true; + while(test){ + if(f1==0.0){ + gperl= g1; + test=false; + } + if(f2==0.0){ + gperl=g2; + test=false; + } + if(test){ + g3=0.5*(g1+g2); + f3=g3-concentration*Sucrose.density(g3,temperature)/100; + if(f3==0.0){ + gperl=g3; + test=false; + } + else{ + if(f3*f1>0){ + g1=g3; + } + else{ + g2=g3; + } + f1=g1-concentration*Sucrose.density(g1,temperature)/100; + f2=g2-concentration*Sucrose.density(g2,temperature)/100; + if(Math.abs(g1-g2)<tol){ + gperl=0.5*(g1+g2); + test=false; + } + } + j++; + if(j>itermax){ + throw new IllegalArgumentException("number of iteractions in bisection exceeded"); + } + } + } + + return gperl; + } +} diff --git a/src/main/java/flanagan/physprop/Water.java b/src/main/java/flanagan/physprop/Water.java new file mode 100755 index 0000000000000000000000000000000000000000..e2b484377fdf631d01c84e6241bcf40e88c1b694 --- /dev/null +++ b/src/main/java/flanagan/physprop/Water.java @@ -0,0 +1,99 @@ +/* +* Water Class +* +* Methods for returning the physical properties of water: +* viscosity, density, refractive index, +* electrical permittivity, molecular weight. +* +* Author: Dr Michael Thomas Flanagan. +* +* Created: July 2003 +* Updated: 1 July 2003 and 6 May 2004 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/Water.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) May 2004 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + + +package flanagan.physprop; +import flanagan.interpolation.CubicSpline; +import flanagan.complex.Complex; + +public class Water{ + + public static final double MOLWEIGHT = 18.02; + + // METHODS + // Returns the viscosity (Pa s) of water at a given temperature (Celsius) + // Interpolation - natural cubic spline + // Data - Rubber Handbook + public static double viscosity(double temperature){ + + double[] tempc = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100}; + double[] visc = {0.0017921, 0.0017313, 0.0016728, 0.0016191, 0.0015674, 0.0015188, 0.0014728, 0.0014284, 0.001386, 0.0013462, 0.0013077, 0.0012713, 0.0012363, 0.0012028, 0.0011709, 0.0011404, 0.0011111, 0.0010828, 0.0010559, 0.0010299, 0.001005, 0.000981, 0.0009579, 0.0009358, 0.0009142, 0.0008937, 0.0008737, 0.0008545, 0.000836, 0.000818, 0.0008007, 0.000784, 0.0007679, 0.0007523, 0.0007371, 0.0007225, 0.0007085, 0.0006947, 0.0006814, 0.0006685, 0.000656, 0.0006439, 0.0006321, 0.0006207, 0.0006097, 0.0005988, 0.0005883, 0.0005782, 0.0005683, 0.0005588, 0.0005494, 0.0005404, 0.0005315, 0.0005229, 0.0005146, 0.0005064, 0.0004985, 0.0004907, 0.0004832, 0.0004759, 0.0004688, 0.0004618, 0.000455, 0.0004483, 0.0004418, 0.0004355, 0.0004293, 0.0004233, 0.0004174, 0.0004117, 0.0004061, 0.0004006, 0.0003952, 0.00039, 0.0003849, 0.0003799, 0.000375, 0.0003702, 0.0003655, 0.000361, 0.0003565, 0.0003521, 0.0003478, 0.0003436, 0.0003395, 0.0003355, 0.0003315, 0.0003276, 0.0003239, 0.0003202, 0.0003165, 0.000313, 0.0003095, 0.000306, 0.0003027, 0.0002994, 0.0002962, 0.000293, 0.0002899, 0.0002868, 0.0002838}; + double[] deriv = {0, 1.78373e-006, 6.66507e-006, 3.55981e-007, 3.911e-006, 2.60001e-006, 1.28896e-006, 1.84413e-006, 3.3345e-006, 4.1785e-007, 2.7941e-006, 1.00576e-006, 1.58285e-006, 1.66282e-006, 1.36586e-006, 1.27374e-006, 7.39187e-007, 1.76951e-006, 5.82755e-007, 1.29947e-006, 8.1938e-007, 8.23013e-007, 1.28857e-006, 2.27218e-008, 1.62055e-006, 9.50918e-008, 9.99086e-007, 7.08563e-007, 3.66662e-007, 8.24789e-007, 5.34182e-007, 6.38482e-007, 5.1189e-007, 3.13959e-007, 6.32274e-007, 7.56944e-007, -6.00505e-008, 6.83258e-007, 3.27018e-007, 4.08669e-007, 4.38304e-007, 2.38113e-007, 4.09244e-007, 5.24909e-007, -1.08882e-007, 5.10619e-007, 4.66404e-007, 2.3763e-008, 6.38544e-007, -1.77938e-007, 6.73209e-007, -1.14896e-007, 3.86377e-007, 3.69389e-007, -6.39346e-008, 4.86349e-007, -8.14616e-008, 4.39497e-007, 1.23473e-007, 2.66612e-007, 1.00779e-008, 2.93076e-007, 1.76187e-008, 2.36449e-007, 2.36584e-007, 1.72156e-008, 2.94554e-007, 4.56925e-009, 2.87169e-007, 4.67538e-008, 1.25815e-007, 4.99845e-008, 2.74247e-007, 5.30292e-008, 1.13637e-007, 9.24242e-008, 1.16667e-007, 4.09095e-008, 3.19695e-007, -1.19691e-007, 1.59069e-007, 8.34135e-008, 1.07277e-007, 8.74801e-008, 1.42803e-007, -5.86918e-008, 9.19641e-008, 2.90835e-007, -5.53049e-008, -6.96157e-008, 3.33768e-007, -6.54552e-008, -7.19471e-008, 3.53244e-007, -1.41027e-007, 2.10865e-007, -1.02433e-007, 1.98866e-007, -9.30309e-008, 1.73258e-007, 0}; + double viscosity; + int n = tempc.length; + + if(temperature>=tempc[0] && temperature<=tempc[n-1]){ + viscosity=CubicSpline.interpolate(temperature, tempc, visc, deriv); + } + else{ + throw new IllegalArgumentException("Temperature outside the experimental data limits"); + } + + return viscosity; + } + + // Returns the density (kg m^-3) of water at a given temperature (Celsius) + // Interpolation - natural cubic spline + // Data - Rubber Handbook + public static double density(double temperature){ + + double[] tempc = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}; + double[] dens = {999.87, 999.93, 999.97, 999.99, 1000, 999.99, 999.97, 999.93, 999.88, 999.81, 999.73, 999.63, 999.52, 999.4, 999.27, 999.13, 998.97, 998.8, 998.62, 998.43, 998.23, 998.02, 997.8, 997.56, 997.32, 997.07, 996.81, 996.54, 996.26, 995.07, 995.67, 995.37, 995.05, 994.73, 994.4, 994.06, 993.71, 993.36, 992.99, 992.62, 992.24, 991.86, 991.47, 991.07, 990.66, 990.25, 989.82, 989.4, 988.96, 988.52, 988.07, 987.62, 987.15, 986.69, 986.21, 985.73, 983.24, 980.59, 977.81, 974.89, 971.83, 968.65, 965.34, 961.92, 958.38}; + double[] deriv = {0, -0.0241154, -0.0235383, -0.00173154, -0.0295356, -0.000126193, -0.0299597, -3.51591e-005, -0.0298997, -0.000366034, -0.0286362, -0.00508932, -0.0110066, -0.0108844, -0.00545578, -0.0272925, -0.00537436, -0.0112101, -0.00978527, -0.00964883, -0.0116194, -0.00387347, -0.0328867, 0.0154203, -0.0287945, 0.0397577, -0.190236, 0.661187, -2.51451, 3.93686, -2.49294, 0.634886, -0.166608, 0.0315471, -0.0195801, -0.0132268, 0.0124871, -0.0367217, 0.0143998, -0.0208776, 0.00911065, -0.015565, -0.0068508, -0.0170318, 0.0149782, -0.0428809, 0.0365453, -0.0433004, 0.0166564, -0.0233251, 0.0166439, -0.0432504, 0.0363578, -0.0421807, 0.0123651, -0.00727961, -0.00660195, -0.0047126, -0.00574764, -0.00589685, -0.00426496, -0.00584331, -0.00356178, -0.00630955, 0}; + double density; + int n = tempc.length; + + if(temperature>=tempc[0] && temperature<=tempc[n-1]){ + density=CubicSpline.interpolate(temperature, tempc, dens, deriv); + } + else{ + throw new IllegalArgumentException("Temperature outside the experimental data limits"); + } + return density; + } + + // Calculates and returns the static relative electrical permittivity + // (dielectric constant) of water as a function of temperature. + // Data: CRC Handbook of Chemistry and Physics 56th edition Page E55 + public static double elecPerm(double tempc){ + double temp = tempc-25.0; + + return 78.54*(1.0-4.579e-3*temp + 1.19e-5*temp*temp - 2.8e-8*temp*temp*temp); + } + + // Returns the refractive index of water at a given wavelength (metres) and temperature (Celsius) + // Interpolation - natural bicubic spline + // Uses method in class RefrIndex + // Data - Rubber Handbook + public static double refractIndex(double wavelength, double temperature){ + return RefrIndex.water(wavelength, temperature); + } +} \ No newline at end of file diff --git a/src/main/java/flanagan/plot/Plot.java b/src/main/java/flanagan/plot/Plot.java new file mode 100755 index 0000000000000000000000000000000000000000..58445a0e10fec1e4bca70ab423981980c90d3d87 --- /dev/null +++ b/src/main/java/flanagan/plot/Plot.java @@ -0,0 +1,1576 @@ +/* +* Class Plot +* +* Superclass for the plotting subclasses: +* PlotGraph and PlotPoleZero +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: February 2002 +* REVISED: 20 July 2005, 7 July 2008, 27 July 2008, 11 August 2008 +* +* Copyright (c) 2002 - 2008 +* +* DOCUMENTATION +* http://www.ee.ucl.ac.uk/~mflanaga/java/PlotGraph.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + + +package flanagan.plot; + +import java.awt.*; +import java.io.Serializable; + +import flanagan.math.Fmath; +import flanagan.math.ArrayMaths; +import flanagan.interpolation.CubicSpline; + +public class Plot extends Canvas implements Serializable{ + + protected static final long serialVersionUID = 1L; // serial version unique identifier + + protected double[][] data = null; // data to be plotted + // data[i][] i = 0, 2, 4 . . . x values + // data[i][] i = 1, 3, 5 . . . y values for x[i-1][] + protected double[][] copy = null; // copy of original data to be plotted + protected int nCurves = 0; // number of curves + protected int[] nPoints = null; // number of points points on curve each curve + protected int nmPoints = 0; // number of points points on curve with most points + protected int niPoints = 200; // number of cubic spline interpolation points + protected int[] pointOpt = null; // point plotting option for each curve + // pointOpt = 0: no points plotted + // pointOpt = i where i = 1,2,3,4,5,6,7,8: points plotted + // default options + // curve 1 - open circles + // curve 2 - open squares + // curve 3 - open diamonds + // curve 4 - filled circles + // curve 5 - filled squares + // curve 6 - filled diamonds + // curve 7 - x crosses + // curve 8 - + crosses + // further curves - above sequence repeated + protected int[] pointSize = null; // point size in pixels for each curve + protected int npTypes = 8; // number of point types + protected boolean[] errorBar = null; // true - error bar plotted, flase no error bar plotted - default = false + protected double[][] errors = null; // error bar values - should be an estimate of the sd of the variable + protected double[][] errorsCopy = null; // copy of error bar values + protected int[] lineOpt = null; // line drawing option for each curve + // lineOpt = 0: no line plotted + // lineOpt = 1: cubic spline interpolation line plotted as a continuous line + // lineOpt = 2: cubic spline interpolation line plotted as a dashed line + // lineOpt = 3: line plotted by joining points + // lineOpt = 4: dashed line plotted by joining points + // default - lineOpt = 1 + protected int[] dashLength = null; // dash length in lineOpt = 2 + protected boolean[] minMaxOpt = null;// true - curve included in maximum and minimum axes value calculation + protected boolean[] trimOpt = null; // true - curve trimmed to fit axes rectangle + + protected int fontSize = 14; // text font size + protected int xLen = 625; // length of the x axis in pixels + protected int yLen = 375; // length of the y axis in pixels + protected int xBot = 100; // x coordinate of the bottom of the x axis in pixels + protected int xTop = xBot+xLen; // x coordinate of the top of the x axis in pixels + protected int yTop = 110; // y coordinate of the top of the y axis in pixels + protected int yBot = yTop+yLen; // y coordinate of the bottom of the y axis in pixels + + protected double xLow = 0; // scaled lower limit data value of the x axis + protected double xHigh = 0; // scaled upper limit data value of the x axis + protected double yLow = 0; // scaled lower limit data value of the y axis + protected double yHigh = 0; // scaled upper limit data value of the y axis + protected int xFac = 0; // decadic exponent of x axis scaling factor + protected int yFac = 0; // decadic exponent of y axis scaling factor + protected int xTicks = 0; // number of x axis ticks + protected int yTicks = 0; // number of y axis ticks + + protected double xMin = 0.0D; // minimum x data value + protected double xMax = 0.0D; // maximum x data value + protected double yMin = 0.0D; // minimum y data value + protected double yMax = 0.0D; // maximum y data value + + protected double xOffset = 0.0D; // xaxis data value offset + protected double yOffset = 0.0D; // y axis data value offset + protected boolean noXoffset = false; // no x axis offset allowed if true + protected boolean noYoffset = false; // no y axis offset allowed if true + protected double xLowFac = 0.75D; // x axis data setting low factor + protected double yLowFac = 0.75D; // y axis data setting low factor + + protected String graphTitle = " "; // graph title + protected String graphTitle2 = " "; // graph title (secondline) + protected String xAxisLegend = " "; // x axis legend title + protected String xAxisUnits = " "; // x axis unit name, e.g. V, ohm + protected String yAxisLegend = " "; // y axis legend title + protected String yAxisUnits = " "; // x axis unit name + + protected boolean xZero = false; // if true - a (x=0) zero line is required + protected boolean yZero = false; // if true - a (y=0) zero line required + protected boolean noXunits = true; // if true - no x axis units + protected boolean noYunits = true; // if true - no y axis units + + protected double[] xAxisNo = new double[50]; // x axis legend numbers as double + protected double[] yAxisNo = new double[50]; // y axis legend numbers as double + protected String[] xAxisChar = new String[50]; // x axis legend numbers as char + protected String[] yAxisChar = new String[50]; // y axis legend numbers as char + protected int[] axisTicks = new int[50]; // no of ticks for scaled lengths + + protected static double dataFill = 3.0e200; // value used to initialise data array by Plot.data() + + + // Constructor + //One 2-dimensional data arrays + public Plot(double[][] data){ + this.initialise(data); + } + + // Constructor + //Two 1-dimensional data arrays + public Plot(double[] xdata, double[] ydata){ + int xl = xdata.length; + int yl = ydata.length; + if(xl!=yl)throw new IllegalArgumentException("x-data length is not equal to the y-data length"); + double[][] data = new double[2][xl]; + for(int i=0; i<xl; i++){ + data[0][i] = xdata[i]; + data[1][i] = ydata[i]; + } + this.initialise(data); + } + + // Initialisation + private void initialise(double[][] cdata){ + + // Calculate number of curves + this.nCurves = cdata.length/2; + + // Initialize 1D class arrays + this.nPoints = new int[nCurves]; + this.lineOpt = new int[nCurves]; + this.dashLength = new int[nCurves]; + this.trimOpt = new boolean[nCurves]; + this.minMaxOpt = new boolean[nCurves]; + this.pointOpt = new int[nCurves]; + this.pointSize = new int[nCurves]; + this.errorBar = new boolean[nCurves]; + + // Calculate maximum number of points on a single curve + this.nmPoints = 0; + int ll = 0; + for(int i=0; i<2*nCurves; i++){ + if((ll=cdata[i].length)>nmPoints)nmPoints=ll; + } + + // Initialize class 2D arrays + this.data = new double[2*nCurves][nmPoints]; + this.copy = new double[2*nCurves][nmPoints]; + this.errors = new double[nCurves][nmPoints]; + this.errorsCopy = new double[nCurves][nmPoints]; + + + // Calculate curve lengths + // and check all individual curves have an equal number of abscissae and ordinates + int k = 0, l1 = 0, l2 = 0; + boolean testlen=true; + for(int i=0; i<nCurves; i++){ + k=2*i; + testlen=true; + l1=cdata[k].length; + l2=cdata[k+1].length; + if(l1!=l2)throw new IllegalArgumentException("an x and y array length differ"); + nPoints[i]=l1; + + } + + // Remove both abscissae and ordinates for points equal to dataFill + k=0; + boolean testopt=true; + for(int i=0; i<nCurves; i++){ + testlen=true; + l1=nPoints[i]; + while(testlen){ + if(l1<0)throw new IllegalArgumentException("curve array index "+k+ ": blank array"); + if(cdata[k][l1-1]==dataFill){ + if(cdata[k+1][l1-1]==dataFill){ + l1--; + testopt=false; + } + else{ + testlen=false; + } + } + else{ + testlen=false; + } + } + nPoints[i]=l1; + k+=2; + } + + // Sort arrays into ascending order + k = 0; + for(int i=0; i<nCurves; i++){ + double[][] xxx = new double[2][nPoints[i]]; + for(int j=0; j<nPoints[i]; j++){ + xxx[0][j] = cdata[k][j]; + xxx[1][j] = cdata[k+1][j]; + } + xxx = doubleSelectionSort(xxx); + for(int j=0; j<nPoints[i]; j++){ + cdata[k][j] = xxx[0][j]; + cdata[k+1][j] = xxx[1][j]; + } + k += 2; + } + + // initialize class data variables + k=0; + int kk=1; + for(int i=0; i<nCurves; i++){ + + // reverse order if all abscissae are in descending order + int rev = 1; + for(int j=1; j<nPoints[i]; j++){ + if(cdata[k][j]<cdata[k][j-1])rev++; + } + if(rev==nPoints[i]){ + double[] hold = new double[nPoints[i]]; + for(int j=0; j<nPoints[i]; j++)hold[j] = cdata[k][j]; + for(int j=0; j<nPoints[i]; j++)cdata[k][j] = hold[nPoints[i]-j-1]; + for(int j=0; j<nPoints[i]; j++)hold[j] = cdata[k+1][j]; + for(int j=0; j<nPoints[i]; j++)cdata[k+1][j] = hold[nPoints[i]-j-1]; + } + + // copy arrays + for(int j=0; j<nPoints[i]; j++){ + this.data[k][j]=cdata[k][j]; + this.data[k+1][j]=cdata[k+1][j]; + this.copy[k][j]=cdata[k][j]; + this.copy[k+1][j]=cdata[k+1][j]; + } + + this.lineOpt[i] = 1; + this.dashLength[i] = 5; + this.trimOpt[i] = false; + if(this.lineOpt[i]==1)trimOpt[i] = true; + this.minMaxOpt[i]=true; + this.pointSize[i]= 6; + this.errorBar[i]= false; + this.pointOpt[i] = kk; + k+=2; + kk++; + if(kk>npTypes)kk = 1; + } + } + + // sort x elements into ascending order with matching switches of y elements + // using selection sort method + public static double[][] doubleSelectionSort(double[][] aa){ + int index = 0; + int lastIndex = -1; + int n = aa[0].length; + double holdx = 0.0D; + double holdy = 0.0D; + double[][] bb = new double[2][n]; + for(int i=0; i<n; i++){ + bb[0][i]=aa[0][i]; + bb[1][i]=aa[1][i]; + } + + + while(lastIndex != n-1){ + index = lastIndex+1; + for(int i=lastIndex+2; i<n; i++){ + if(bb[0][i]<bb[0][index]){ + index=i; + } + } + lastIndex++; + holdx=bb[0][index]; + bb[0][index]=bb[0][lastIndex]; + bb[0][lastIndex]=holdx; + holdy=bb[1][index]; + bb[1][index]=bb[1][lastIndex]; + bb[1][lastIndex]=holdy; + + } + return bb; + } + + + //Create a data array initialised to dataFill; + public static double[][] data(int n, int m){ + double[][] d = new double[2*n][m]; + for(int i=0; i<2*n; i++){ + for(int j=0; j<m; j++){ + d[i][j]=dataFill; + } + } + return d; + } + + //Change the value used to initialise the datarray + public static void setDataFillValue(double dataFill){ + Plot.dataFill=dataFill; + } + + //Get the value used to initialise the datarray + public static double getDataFillValue(){ + return Plot.dataFill; + } + + // Enter primary graph title + public void setGraphTitle(String graphTitle){ + this.graphTitle=graphTitle; + } + + // Enter second line to graph title + public void setGraphTitle2(String graphTitle2){ + this.graphTitle2=graphTitle2; + } + + // Enter x axis legend + public void setXaxisLegend(String xAxisLegend){ + this.xAxisLegend=xAxisLegend; + } + + // Enter y axis legend + public void setYaxisLegend(String yAxisLegend){ + this.yAxisLegend=yAxisLegend; + } + + // Enter x axis unit name + public void setXaxisUnitsName(String xAxisUnits){ + this.xAxisUnits=xAxisUnits; + this.noXunits=false; + } + + // Enter y axis unit name + public void setYaxisUnitsName(String yAxisUnits){ + this.yAxisUnits=yAxisUnits; + this.noYunits=false; + } + + // Get pixel length of the x axis + public int getXaxisLen(){ + return this.xLen; + } + + // Get pixel length of the y axis + public int getYaxisLen(){ + return this.yLen; + } + + // Get pixel start of the x axis + public int getXlow(){ + return this.xBot; + } + + // Get pixel end of the y axis + public int getYhigh(){ + return this.yTop; + } + + // Get point size in pixels + public int[] getPointsize(){ + return this.pointSize; + } + + // Get dash length in pixels + public int[] getDashlength(){ + return this.dashLength; + } + + // Get the x axis low factor + public double getXlowFac(){ + return 1.0D-this.xLowFac; + } + + // Get the y axis low factor + public double getYlowFac(){ + return 1.0D-this.yLowFac; + } + + // Get the x axis minimum value + public double getXmin(){ + return this.xMin; + } + + // Get the x axis maximum value + public double getXmax(){ + return this.xMax; + } + + // Get the y axis minimum value + public double getYmin(){ + return this.yMin; + } + + // Get the y axis maximum value + public double getYmax(){ + return this.yMax; + } + + // get line plotting option + public int[] getLine(){ + return this.lineOpt; + } + + // Get point plotting options + public int[] getPoint(){ + return this.pointOpt; + } + + // Get the number of points to be used in the cubic spline interpolation + public int getNiPoints(){ + return this.niPoints; + } + + // Get font size + public int getFontSize(){ + return this.fontSize; + } + + // Reset pixel length of the x axis + public void setXaxisLen(int xLen){ + this.xLen=xLen; + this.update(); + } + + // Reset pixel length of the y axis + public void setYaxisLen(int yLen){ + this.yLen=yLen; + this.update(); + } + + // Reset pixel start of the x axis + public void setXlow(int xBot){ + this.xBot=xBot; + this.update(); + } + + // Reset pixel end of the y axis + public void setYhigh(int yTop){ + this.yTop=yTop; + this.update(); + } + + // Reset the x axis low factor + public void setXlowFac(double xLowFac){ + this.xLowFac=1.0D-xLowFac; + } + + // Reset the y axis low factor + public void setYlowFac(double yLowFac){ + this.yLowFac=1.0D-yLowFac; + } + + // Reset the x axis offset option + public void setNoXoffset(boolean noXoffset){ + this.noXoffset=noXoffset; + } + + // Reset the y axis offset option + public void setNoYoffset(boolean noYoffset){ + this.noYoffset=noYoffset; + } + + // Reset both the x and y axis offset options to the same optio + public void setNoOffset(boolean nooffset){ + this.noXoffset=nooffset; + this.noYoffset=nooffset; + } + + // Get the x axis offset option + public boolean getNoXoffset(){ + return this.noXoffset; + } + + // RGet the y axis offset option + public boolean getNoYoffset(){ + return this.noYoffset; + } + + // Update axis pixel position parameters + protected void update(){ + this.xTop = this.xBot + this.xLen; + this.yBot = this.yTop + this.yLen; + } + + // Overwrite line plotting option with different options for individual curves + public void setLine(int[] lineOpt){ + int n=lineOpt.length; + if(n!=nCurves)throw new IllegalArgumentException("input array of wrong length"); + for(int i=0; i<n; i++)if(lineOpt[i]<0 || lineOpt[i]>4)throw new IllegalArgumentException("lineOpt must be 0, 1, 2, 3 or 4"); + this.lineOpt=lineOpt; + + // check if data supports cubic spline interpolation if lineOpt = 1 or 2 + for(int i=0; i<this.lineOpt.length; i++){ + if(this.lineOpt[i]==1 || this.lineOpt[i]==2){ + // check if some points reverse direction + boolean test0 = false; + for(int j=1; j<this.nPoints[i]; j++){ + if(data[i][j]<data[i][j-1])test0=true; + } + if(test0){ + // check if y all in ascending order + int rev = 1; + for(int j=1; j<nPoints[i]; j++){ + if(data[2*i][j]>data[2*i][j-1])rev++; + } + if(rev==nPoints[i]){ + lineOpt[i]=-lineOpt[i]; + } + else{ + // check if y all in descending order + rev = 1; + for(int j=1; j<nPoints[i]; j++){ + if(data[2*i][j]<data[2*i][j-1])rev++; + } + if(rev==nPoints[i]){ + // reverse order of y + double[] hold = new double[nPoints[i]]; + for(int j=0; j<nPoints[i]; j++)hold[j] = data[i][j]; + for(int j=0; j<nPoints[i]; j++)data[i][j] = hold[nPoints[i]-j-1]; + for(int j=0; j<nPoints[i]; j++)hold[j] = data[2*i][j]; + for(int j=0; j<nPoints[i]; j++)data[2*i][j] = hold[nPoints[i]-j-1]; + this.lineOpt[i] = - lineOpt[i]; + } + else{ + System.out.println("Curve "+i+" will not support interpolation"); + System.out.println("Straight connecting line option used"); + if(this.lineOpt[i]==1) this.lineOpt[i] = 3; + if(this.lineOpt[i]==2) this.lineOpt[i] = 4; + } + } + } + } + } + } + + // Overwrite line plotting option with a single option for all curves + public void setLine(int slineOpt){ + if(slineOpt<0 || slineOpt>3)throw new IllegalArgumentException("lineOpt must be 0, 1, 2 or 3"); + for(int i=0; i<this.nCurves; i++)this.lineOpt[i]=slineOpt; + } + + // Overwrite dash length with different options for individual curves + public void setDashLength(int[] dashLength){ + if(dashLength.length!=nCurves)throw new IllegalArgumentException("input array of wrong length"); + this.dashLength=dashLength; + } + + // Overwrite dashLength with a single option for all curves + public void setDashLength(int sdashLength){ + for(int i=0; i<this.nCurves; i++)this.dashLength[i]=sdashLength; + } + + // Overwrite point plotting option with different options for individual curves + public void setPoint(int[] pointOpt){ + int n=pointOpt.length; + if(n!=nCurves)throw new IllegalArgumentException("input array of wrong length"); + for(int i=0; i<n; i++)if(pointOpt[i]<0 || pointOpt[i]>8)throw new IllegalArgumentException("pointOpt must be 0, 1, 2, 3, 4, 5, 6, 7, or 8"); + this.pointOpt=pointOpt; + } + + // Overwrite point plotting option with a single option for all curves + public void setPoint(int spointOpt){ + if(spointOpt<0 || spointOpt>8)throw new IllegalArgumentException("pointOpt must be 0, 1, 2, 3, 4, 5, 6, 7, or 8"); + for(int i=0; i<this.nCurves; i++)this.pointOpt[i]=spointOpt; + } + + // Overwrite point size with different options for individual curves + public void setPointSize(int[] mpointSize){ + if(mpointSize.length!=nCurves)throw new IllegalArgumentException("input array of wrong length"); + for(int i=0; i<this.nCurves; i++){ + if(mpointSize[i]!=(mpointSize[i]/2)*2)mpointSize[i]++; + this.pointSize[i]=mpointSize[i]; + } + } + + // Overwrite point size with a single option for all curves + public void setPointSize(int spointSize){ + if(spointSize%2!=0)spointSize++; + for(int i=0; i<this.nCurves; i++)this.pointSize[i]=spointSize; + } + + // Set errorBar values + // Must set each curve individually + // nc is the curve identifier (remember curves start at 0) + // err are the error bar values which should be an estimate of the standard devition of the experimental point + public void setErrorBars(int nc, double[] err){ + if(err.length!=this.nPoints[nc])throw new IllegalArgumentException("input array of wrong length"); + this.errorBar[nc] = true; + for(int i=0; i<this.nPoints[nc]; i++){ + this.errors[nc][i] = err[i]; + this.errorsCopy[nc][i] = err[i]; + } + } + + // overwrite the number of points to be used in the cubic spline interpolation + public void setNiPoints(int niPoints){ + this.niPoints=niPoints; + } + + // overwrite the font size + public void setFontSize(int fontSize){ + this.fontSize=fontSize; + } + + // overwrite the trim option + public void setTrimOpt(boolean[] trim){ + this.trimOpt=trim; + } + + // overwrite the minMaxOpt option + public void setMinMaxOpt(boolean[] minmax){ + this.minMaxOpt=minmax; + } + + // Calculate scaling factors + public static int scale(double mmin, double mmax){ + int fac=0; + double big=0.0D; + boolean test=false; + + if(mmin>=0.0 && mmax>0.0){ + big=mmax; + test=true; + } + else{ + if(mmin<0.0 && mmax<=0.0){ + big=-mmin; + test=true; + } + else{ + if(mmax>0.0 && mmin<0.0){ + big=Math.max(mmax, -mmin); + test=true; + } + } + } + + if(test){ + if(big>100.0){ + while(big>1.0){ + big/=10.0; + fac--; + } + } + if(big<=0.01){ + while(big<=0.10){ + big*=10.0; + fac++; + } + } + } + return fac; + } + + // Set low value on axis + public static void limits(double low, double high, double lowfac, double[]limits){ + + double facl = 1.0D; + double fach = 1.0D; + if(Math.abs(low)<1.0D)facl=10.0D; + if(Math.abs(low)<0.1D)facl=100.0D; + if(Math.abs(high)<1.0D)fach=10.0D; + if(Math.abs(high)<0.1D)fach=100.0D; + + double ld=Math.floor(10.0*low*facl)/facl; + double hd=Math.ceil(10.0*high*fach)/fach; + + if(ld>=0.0D && hd>0.0D){ + if(ld<lowfac*hd){ + ld=0.0; + } + } + if(ld<0.0D && hd<=0.0D){ + if(-hd <= -lowfac*ld){ + hd=0.0; + } + } + limits[0] = ld/10.0; + limits[1] = hd/10.0; + } + + // Calculate axis offset value + public static double offset(double low, double high){ + + double diff = high - low; + double sh = Fmath.sign(high); + double sl = Fmath.sign(low); + double offset=0.0D; + int eh=0, ed=0; + + if(sh == sl){ + ed=(int)Math.floor(Fmath.log10(diff)); + if(sh==1){ + eh=(int)Math.floor(Fmath.log10(high)); + if(eh-ed>1)offset = Math.floor(low*Math.pow(10, -ed))*Math.pow(10,ed); + } + else{ + eh=(int)Math.floor(Fmath.log10(Math.abs(low))); + if(eh-ed>1)offset = Math.floor(high*Math.pow(10, -ed))*Math.pow(10,ed); + } + } + return offset; + } + + + // Calculate scaling and offset values for both axes + public void axesScaleOffset(){ + + double[] limit = new double[2]; + + // tranfer data from copy to enable redrawing + int k=0; + for(int i=0; i<nCurves; i++){ + for(int j=0; j<nPoints[i]; j++){ + this.data[k][j]=this.copy[k][j]; + this.data[k+1][j]=this.copy[k+1][j]; + this.errors[i][j]=this.errorsCopy[i][j]; + if(this.errorBar[i])this.errors[i][j]+=this.data[k+1][j]; + } + k+=2; + } + + // Find mimium and maximum data values + minMax(); + + // Calculate x axis offset values and subtract it from the data + if(!noXoffset)this.xOffset=offset(this.xMin, this.xMax); + if(this.xOffset!=0.0){ + k=0; + for(int i=0; i<this.nCurves; i++){ + for(int j=0; j<this.nPoints[i]; j++){ + this.data[k][j] -= this.xOffset; + } + k+=2; + } + this.xMin -= this.xOffset; + this.xMax -= this.xOffset; + } + + // Calculate y axis offset values and subtract it from the data + if(!noYoffset)this.yOffset=offset(this.yMin, this.yMax); + if(this.yOffset!=0.0){ + k=1; + for(int i=0; i<this.nCurves; i++){ + for(int j=0; j<this.nPoints[i]; j++){ + this.data[k][j] -= this.yOffset; + if(this.errorBar[i])this.errors[i][j] -= this.yOffset; + } + k+=2; + } + this.yMin -= this.yOffset; + this.yMax -= this.yOffset; + } + + // Calculate x axes scale values and scale data + this.xFac = scale(this.xMin, this.xMax); + if(this.xFac!=0){ + k=0; + for(int i=0; i<this.nCurves; i++){ + for(int j=0; j<this.nPoints[i]; j++){ + this.data[k][j] *= Math.pow(10, this.xFac+1); + } + k+=2; + } + this.xMin *= Math.pow(10, this.xFac+1); + this.xMax *= Math.pow(10, this.xFac+1); + } + + // Calculate y axes scale values and scale data + this.yFac = scale(this.yMin, this.yMax); + if(this.yFac!=0){ + k=1; + for(int i=0; i<this.nCurves; i++){ + for(int j=0; j<this.nPoints[i]; j++){ + this.data[k][j] *= Math.pow(10, yFac+1); + if(this.errorBar[i])this.errors[i][j] *= Math.pow(10, this.yFac+1); + } + k+=2; + } + this.yMin *= Math.pow(10, this.yFac+1); + this.yMax *= Math.pow(10, this.yFac+1); + } + + // Calculate scaled low and high values + // x axis + limits(this.xMin, this.xMax, this.xLowFac, limit); + this.xLow = limit[0]; + this.xHigh = limit[1]; + if(xLow<0 && xHigh>0)xZero=true; + // y axis + limits(this.yMin, this.yMax, this.yLowFac, limit); + this.yLow = limit[0]; + this.yHigh = limit[1]; + if(yLow<0 && yHigh>0)yZero=true; + + // Calculate tick parameters + // x axis + this.xTicks = ticks(this.xLow, this.xHigh, this.xAxisNo, this.xAxisChar); + this.xHigh = this.xAxisNo[this.xTicks-1]; + if(this.xLow!=this.xAxisNo[0]){ + if(this.xOffset!=0.0D){ + this.xOffset = this.xOffset - this.xLow + this.xAxisNo[0]; + } + this.xLow = this.xAxisNo[0]; + } + // y axis + this.yTicks = ticks(this.yLow, this.yHigh, this.yAxisNo, this.yAxisChar); + this.yHigh = this.yAxisNo[this.yTicks-1]; + if(this.yLow!=this.yAxisNo[0]){ + if(this.yOffset!=0.0D){ + this.yOffset = this.yOffset - this.yLow + this.yAxisNo[0]; + } + this.yLow = this.yAxisNo[0]; + } + + } + + // Calculate axis ticks and tick values + public static int ticks(double low, double high, double[] tickval, String[] tickchar){ + + + // Find range + int[] trunc = {1, 1, 1, 2, 3}; + double[] scfac1 = {1.0, 10.0, 1.0, 0.1, 0.01}; + double[] scfac2 = {1.0, 1.0, 0.1, 0.01, 0.001}; + + double rmax = Math.abs(high); + double temp = Math.abs(low); + if(temp>rmax)rmax = temp; + int range = 0; + if(rmax<=100.0D){ + range = 1; + } + if(rmax<=10.0D){ + range = 2; + } + if(rmax<=1.0D){ + range = 3; + } + if(rmax<=0.1D){ + range = 4; + } + if(rmax>100.0D || rmax<0.01)range = 0; + + // Calculate number of ticks + double inc = 0.0D; + double bot = 0.0D; + double top = 0.0D; + int sgn = 0; + int dirn = 0; + if(high>0.0D && low>=0.0D){ + inc = Math.ceil((high-low)/scfac1[range])*scfac2[range]; + dirn = 1; + bot = low; + top = high; + sgn = 1; + } + else{ + if(high<=0 && low<0.0D){ + inc = Math.ceil((high-low)/scfac1[range])*scfac2[range]; + dirn = -1; + bot = high; + top = low; + sgn = -1; + } + else{ + double up = Math.abs(Math.ceil(high)); + double down = Math.abs(Math.floor(low)); + int np = 0; + if(up>=down){ + dirn = 2; + np = (int)Math.rint(10.0*up/(up+down)); + inc = Math.ceil((high*10/np)/scfac1[range])*scfac2[range]; + bot = 0.0D; + top = high; + sgn = 1; + } + else{ + dirn = -2; + np = (int)Math.rint(10.0D*down/(up+down)); + inc = Math.ceil((Math.abs(low*10/np))/scfac1[range])*scfac2[range]; + bot = 0.0D; + top = low; + sgn = -1; + } + } + } + + int nticks = 1; + double sum = bot; + boolean test = true; + while(test){ + sum = sum + sgn*inc; + nticks++; + if(Math.abs(sum)>=Math.abs(top))test=false; + } + + // Calculate tick values + int npExtra = 0; + double[] ttickval = null;; + switch(dirn){ + case 1: ttickval = new double[nticks]; + tickval[0]=Fmath.truncate(low, trunc[range]); + for(int i=1; i<nticks; i++){ + tickval[i] = Fmath.truncate(tickval[i-1]+inc, trunc[range]); + } + break; + case -1: ttickval = new double[nticks]; + ttickval[0]=Fmath.truncate(high, trunc[range]); + for(int i=1; i<nticks; i++){ + ttickval[i] = Fmath.truncate(ttickval[i-1]-inc, trunc[range]); + } + ttickval = Fmath.reverseArray(ttickval); + for(int i=0; i<nticks; i++)tickval[i] = ttickval[i]; + break; + case 2: npExtra = (int)Math.ceil(-low/inc); + nticks += npExtra; + ttickval = new double[nticks]; + tickval[0]=Fmath.truncate(-npExtra*inc, trunc[range]); + for(int i=1; i<nticks; i++){ + tickval[i] = Fmath.truncate(tickval[i-1]+inc, trunc[range]); + } + break; + case -2: npExtra = (int)Math.ceil(high/inc); + nticks += npExtra; + ttickval = new double[nticks]; + ttickval[0]=Fmath.truncate(npExtra*inc, trunc[range]); + for(int i=1; i<nticks; i++){ + ttickval[i] = Fmath.truncate(ttickval[i-1]-inc, trunc[range]); + } + ttickval = Fmath.reverseArray(ttickval); + for(int i=0; i<nticks; i++)tickval[i] = ttickval[i]; + break; + } + + // ensure a zero value is truly zero and not a zero with rounding errors, e.g. 1e-17 + ArrayMaths am = new ArrayMaths(tickval); + double max = am.maximum(); + double min = Math.abs(am.minimum()); + boolean testZero = true; + int counter = 0; + while(testZero){ + if(Math.abs(tickval[counter])<max*1e-4 || Math.abs(tickval[counter])<min*1e-4){ + tickval[counter] = 0.0; + testZero = false; + } + else{ + counter++; + if(counter>=nticks)testZero = false; + } + } + + // set String form of tick values + for(int i=0; i<nticks; i++){ + tickchar[i] = String.valueOf(tickval[i]); + tickchar[i] = tickchar[i].trim(); + } + + return nticks; + } + + // Find minimum and maximum x and y values + public void minMax(){ + boolean test = true; + + int ii=0; + while(test){ + if(this.minMaxOpt[ii]){ + test=false; + this.xMin=this.data[2*ii][0]; + this.xMax=this.data[2*ii][0]; + this.yMin=this.data[2*ii+1][0]; + if(this.errorBar[ii])this.yMin=2.0D*this.yMin-this.errors[ii][0]; + this.yMax=this.data[2*ii+1][0]; + if(this.errorBar[ii])this.yMax=errors[ii][0]; + } + else{ + ii++; + if(ii>nCurves)throw new IllegalArgumentException("At least one curve must be included in the maximum/minimum calculation"); + } + } + + int k=0; + double yMint=0.0D, yMaxt=0.0D; + for(int i=0; i<this.nCurves; i++){ + if(minMaxOpt[i]){ + for(int j=0; j<this.nPoints[i]; j++){ + if(this.xMin>this.data[k][j])this.xMin=this.data[k][j]; + if(this.xMax<this.data[k][j])this.xMax=this.data[k][j]; + yMint=this.data[k+1][j]; + if(errorBar[i])yMint=2.0D*yMint-errors[i][j]; + if(this.yMin>yMint)this.yMin=yMint; + yMaxt=this.data[k+1][j]; + if(errorBar[i])yMaxt=errors[i][j]; + if(this.yMax<yMaxt)this.yMax=yMaxt; + } + } + k+=2; + } + + if(this.xMin==this.xMax){ + if(this.xMin==0.0D){ + this.xMin=0.1D; + this.xMax=0.1D; + } + else{ + if(this.xMin<0.0D){ + this.xMin=this.xMin*1.1D; + } + else{ + this.xMax=this.xMax*1.1D; + } + } + } + + if(this.yMin==this.yMax){ + if(this.yMin==0.0D){ + this.yMin=0.1D; + this.yMax=0.1D; + } + else{ + if(this.yMin<0.0D){ + this.yMin=this.yMin*1.1D; + } + else{ + this.yMax=this.yMax*1.1D; + } + } + } + } + + // Convert offset value to a string and reformat if in E format + protected static String offsetString(double offset){ + String stroffset = String.valueOf(offset); + String substr1="", substr2="", substr3=""; + String zero ="0"; + int posdot = stroffset.indexOf('.'); + int posexp = stroffset.indexOf('E'); + + if(posexp==-1){ + return stroffset; + } + else{ + substr1 = stroffset.substring(posexp+1); + int n = Integer.parseInt(substr1); + substr1 = stroffset.substring(0,posexp); + if(n>=0){ + for(int i=0; i<n; i++){ + substr1 = substr1 + zero; + } + return substr1; + } + else{ + substr2 = substr1.substring(0, posdot+1); + substr3 = substr1.substring(posdot+1); + for(int i=0; i<-n; i++){ + substr2 = substr1 + zero; + } + substr2 = substr2 + substr3; + return substr2; + } + } + } + + // check whether point in line segment is to be drawn + public boolean printCheck(boolean trim, int xoldpoint, int xnewpoint, int yoldpoint, int ynewpoint){ + + boolean btest2=true; + + if(trim){ + if(xoldpoint<xBot)btest2=false; + if(xoldpoint>xTop)btest2=false; + if(xnewpoint<xBot)btest2=false; + if(xnewpoint>xTop)btest2=false; + if(yoldpoint>yBot)btest2=false; + if(yoldpoint<yTop)btest2=false; + if(ynewpoint>yBot)btest2=false; + if(ynewpoint<yTop)btest2=false; + } + + return btest2; + } + + // Draw graph + public void graph(Graphics g){ + + // Set font type and size + g.setFont(new Font("serif", Font.PLAIN, this.fontSize)); + FontMetrics fm = g.getFontMetrics(); + + // calculation of all graphing parameters and data scaling + axesScaleOffset(); + + // Draw title, legends and axes + String xoffstr = offsetString(xOffset); + String yoffstr = offsetString(yOffset); + String bunit1 = " /( "; + String bunit2 = " )"; + String bunit3 = " / "; + String bunit4 = " "; + String bunit5 = " x 10"; + String bunit6 = "10"; + String nounit = " "; + String xbrack1 = bunit1; + String xbrack2 = bunit2; + String xbrack3 = bunit5; + if(this.xFac==0){ + xbrack1 = bunit3; + xbrack2 = ""; + xbrack3 = ""; + } + String ybrack1 = bunit1; + String ybrack2 = bunit2; + String ybrack3 = bunit5; + if(this.yFac==0){ + ybrack1 = bunit3; + ybrack2 = ""; + ybrack3 = ""; + } + if(noXunits){ + if(xFac==0){ + xbrack1=nounit; + xbrack2=nounit; + xbrack3=nounit; + } + else{ + xbrack1=bunit3; + xbrack2=bunit4; + xbrack3=bunit6; + } + } + if(noYunits){ + if(yFac==0){ + ybrack1=nounit; + ybrack2=nounit; + ybrack3=nounit; + } + else{ + ybrack1=bunit3; + ybrack2=bunit4; + ybrack3=bunit6; + } + } + + double xLen=xTop-xBot; + double yLen=yBot-yTop; + + // Print title + String sp = " + ", sn = " - "; + String ss=sn; + g.drawString(this.graphTitle+" ", 15,15); + g.drawString(this.graphTitle2+" ", 15,35); + if(this.xOffset<0){ + ss=sp; + xOffset=-xOffset; + } + + // Print legends + int sw=0; + String ssx="", ssy="", sws1="", sws2=""; + if(this.xFac==0 && this.xOffset==0){ + g.drawString(this.xAxisLegend+xbrack1+this.xAxisUnits+xbrack2, xBot-4,yBot+32); + } + else{ + if(this.xOffset==0){ + ssx = this.xAxisLegend + xbrack1 + this.xAxisUnits + xbrack3; + sw = fm.stringWidth(ssx); + g.drawString(ssx, xBot-4,yBot+42); + sws1=String.valueOf(-this.xFac-1); + g.drawString(sws1, xBot-4+sw+1,yBot+32); + sw += fm.stringWidth(sws1); + g.drawString(xbrack2, xBot-4+sw+1,yBot+42); + } + else{ + if(this.xFac==0){ + g.drawString(this.xAxisLegend + ss + xoffstr + xbrack1+this.xAxisUnits+xbrack2, xBot-4,yBot+30); + } + else{ + ssx = this.xAxisLegend + ss + xoffstr + xbrack1+this.xAxisUnits+xbrack3; + sw = fm.stringWidth(ssx); + g.drawString(ssx, xBot-4,yBot+37); + sws1 = String.valueOf(-this.xFac-1); + g.drawString(sws1, xBot-4+sw+1,yBot+32); + sw += fm.stringWidth(sws1); + g.drawString(xbrack2, xBot-4+sw+1,yBot+37); + } + } + } + + ss=sn; + if(yOffset<0){ + ss=sp; + yOffset=-yOffset; + } + + if(yFac==0 && yOffset==0){ + g.drawString(this.yAxisLegend+" ", 15,yTop-25); + g.drawString(ybrack1+this.yAxisUnits+ybrack2, 15,yTop-10); + } + else{ + if(yOffset==0){ + g.drawString(this.yAxisLegend, 15,yTop-35); + sws1 = ybrack1+this.yAxisUnits + ybrack3; + g.drawString(sws1, 15,yTop-15); + sw = fm.stringWidth(sws1); + sws2=String.valueOf(-this.yFac-1); + g.drawString(sws2, 15+sw+1,yTop-20); + sw += fm.stringWidth(sws2); + g.drawString(ybrack2, 15+sw+1,yTop-15); + } + else{ + if(yFac==0){ + g.drawString(this.yAxisLegend + ss + yoffstr, 15,yTop-25); + g.drawString(ybrack1+this.yAxisUnits+ybrack2, 15,yTop-10); + } + else{ + ssy = this.yAxisLegend + ss + yoffstr; + g.drawString(ssy, 15,yTop-35); + sws1 = ybrack1+this.yAxisUnits + ybrack3; + g.drawString(sws1, 15,yTop-15); + sw = fm.stringWidth(sws1); + sws2=String.valueOf(-this.yFac-1); + g.drawString(sws2, 15+sw+1,yTop-20); + sw += fm.stringWidth(sws2); + g.drawString(ybrack2, 15+sw+1,yTop-15); + } + } + } + + // Draw axes + int zdif=0, zold=0, znew=0, zzer=0; + double csstep=0.0D; + double xdenom=(xHigh-xLow); + double ydenom=(yHigh-yLow); + + g.drawLine(xBot, yBot, xTop, yBot); + g.drawLine(xBot, yTop, xTop, yTop); + g.drawLine(xBot, yBot, xBot, yTop); + g.drawLine(xTop, yBot, xTop, yTop); + + + // Draw zero lines if drawn axes are not at zero and a zero value lies on an axis + if(xZero){ + zdif=8; + zzer=xBot+(int)(((0.0-xLow)/xdenom)*xLen); + g.drawLine(zzer,yTop,zzer,yTop+8); + g.drawLine(zzer,yBot,zzer,yBot-8); + zold=yTop; + while(zold+zdif<yBot){ + znew=zold+zdif; + g.drawLine(zzer, zold, zzer, znew); + zold=znew+zdif; + } + } + + if(yZero){ + zdif=8; + zzer=yBot-(int)(((0.0-yLow)/ydenom)*yLen); + g.drawLine(xBot,zzer,xBot+8,zzer); + g.drawLine(xTop,zzer,xTop-8,zzer); + zold=xBot; + while(zold+zdif<xTop){ + znew=zold+zdif; + g.drawLine(zold, zzer, znew, zzer); + zold=znew+zdif; + } + } + + // Draw tick marks and axis numbers + int xt=0; + //double xtep=(double)(xTop-xBot)/((double)(this.xTicks-1)); + for(int ii=0; ii<this.xTicks; ii++) + { + xt=xBot+(int)(((this.xAxisNo[ii]-xLow)/xdenom)*xLen); + g.drawLine(xt,yBot,xt,yBot-8); + g.drawLine(xt,yTop,xt,yTop+8); + g.drawString(xAxisChar[ii]+" ",xt-4,yBot+18); + } + + int yt=0; + int yCharLenMax=yAxisChar[0].length(); + for(int ii=1; ii<this.yTicks; ii++)if(yAxisChar[ii].length()>yCharLenMax)yCharLenMax=yAxisChar[ii].length(); + int shift = (yCharLenMax-3)*5; + double ytep=(double)(-yTop+yBot)/((double)(this.yTicks-1)); + for(int ii=0; ii<this.yTicks; ii++) + { + yt=yBot-(int)Math.round(ii*ytep); + yt=yBot-(int)(((this.yAxisNo[ii]-yLow)/ydenom)*yLen); + g.drawLine(xBot,yt,xBot+8,yt); + g.drawLine(xTop,yt,xTop-8,yt); + g.drawString(yAxisChar[ii]+" ",xBot-30-shift,yt+4); + } + + int dsum=0; // dashed line counter + boolean dcheck=true; // dashed line check + + // Draw curves + int kk=0; + int xxp=0, yyp=0, yype=0; + int xoldpoint=0, xnewpoint=0, yoldpoint=0, ynewpoint=0; + int ps=0, psh=0, nxpoints=0; + double ics[]= new double[niPoints]; + boolean btest2=true; + + for(int i=0; i<this.nCurves; i++){ + // cubic spline interpolation option + nxpoints=this.nPoints[i]; + double xcs[]= new double[nxpoints]; + double ycs[]= new double[nxpoints]; + + if(lineOpt[i]==1 || lineOpt[i]==2){ + CubicSpline cs = new CubicSpline(this.nPoints[i]); + for(int ii=0; ii<nxpoints; ii++){ + xcs[ii]=this.data[kk][ii]; + } + csstep=(xcs[nxpoints-1]-xcs[0])/(niPoints-1); + ics[0]=xcs[0]; + for(int ii=1; ii<niPoints; ii++){ + ics[ii]=ics[ii-1]+csstep; + } + ics[niPoints-1] = xcs[nxpoints-1]; + for(int ii=0; ii<nxpoints; ii++){ + ycs[ii]=this.data[kk+1][ii]; + } + + cs.resetData(xcs, ycs); + cs.calcDeriv(); + xoldpoint=xBot+(int)(((xcs[0]-xLow)/xdenom)*xLen); + yoldpoint=yBot-(int)(((ycs[0]-yLow)/ydenom)*yLen); + for(int ii=1; ii<niPoints; ii++){ + xnewpoint=xBot+(int)(((ics[ii]-xLow)/xdenom)*xLen); + ynewpoint=yBot-(int)(((cs.interpolate(ics[ii])-yLow)/ydenom)*yLen); + btest2=printCheck(trimOpt[i], xoldpoint, xnewpoint, yoldpoint, ynewpoint); + if(btest2){ + if(this.lineOpt[i]==2){ + dsum++; + if(dsum>dashLength[i]){ + dsum=0; + if(dcheck){ + dcheck=false; + } + else{ + dcheck=true; + } + } + } + if(dcheck)g.drawLine(xoldpoint,yoldpoint,xnewpoint,ynewpoint); + } + xoldpoint=xnewpoint; + yoldpoint=ynewpoint; + } + } + + if(lineOpt[i]==-1 || lineOpt[i]==-2){ + CubicSpline cs = new CubicSpline(this.nPoints[i]); + for(int ii=0; ii<nxpoints; ii++){ + xcs[ii]=this.data[kk][ii]; + } + for(int ii=0; ii<nxpoints; ii++){ + ycs[ii]=this.data[kk+1][ii]; + } + csstep=(ycs[nxpoints-1]-ycs[0])/(niPoints-1); + ics[0]=ycs[0]; + for(int ii=1; ii<niPoints; ii++){ + ics[ii]=ics[ii-1]+csstep; + } + ics[niPoints-1] = ycs[nxpoints-1]; + + cs.resetData(ycs, xcs); + cs.calcDeriv(); + xoldpoint=xBot+(int)(((xcs[0]-xLow)/xdenom)*xLen); + yoldpoint=yBot-(int)(((ycs[0]-yLow)/ydenom)*yLen); + for(int ii=1; ii<niPoints; ii++){ + ynewpoint=yBot+(int)(((ics[ii]-yLow)/ydenom)*yLen); + xnewpoint=xBot-(int)(((cs.interpolate(ics[ii])-xLow)/xdenom)*xLen); + btest2=printCheck(trimOpt[i], xoldpoint, xnewpoint, yoldpoint, ynewpoint); + if(btest2){ + if(this.lineOpt[i]==2){ + dsum++; + if(dsum>dashLength[i]){ + dsum=0; + if(dcheck){ + dcheck=false; + } + else{ + dcheck=true; + } + } + } + if(dcheck)g.drawLine(xoldpoint,yoldpoint,xnewpoint,ynewpoint); + } + xoldpoint=xnewpoint; + yoldpoint=ynewpoint; + } + } + + if(lineOpt[i]==3){ + // Join points option + dsum=0; + dcheck=true; + xoldpoint=xBot+(int)((((this.data[kk][0])-xLow)/xdenom)*xLen); + yoldpoint=yBot-(int)((((this.data[kk+1][0])-yLow)/ydenom)*yLen); + for(int ii=1; ii<nxpoints; ii++){ + xnewpoint=xBot+(int)((((this.data[kk][ii])-xLow)/xdenom)*xLen); + ynewpoint=yBot-(int)((((this.data[kk+1][ii])-yLow)/ydenom)*yLen); + btest2=printCheck(trimOpt[i], xoldpoint, xnewpoint, yoldpoint, ynewpoint); + if(btest2)g.drawLine(xoldpoint,yoldpoint,xnewpoint,ynewpoint); + xoldpoint=xnewpoint; + yoldpoint=ynewpoint; + } + } + + if(lineOpt[i]==4){ + // Join points with dotted line option + + // lines between points + int[] lengths = new int[nxpoints-1]; + double[] gradients = new double[nxpoints-1]; + double[] intercepts = new double[nxpoints-1]; + int totalLength = 0; + xoldpoint=xBot+(int)((((this.data[kk][0])-xLow)/xdenom)*xLen); + yoldpoint=yBot-(int)((((this.data[kk+1][0])-yLow)/ydenom)*yLen); + for(int ii=1; ii<nxpoints; ii++){ + xnewpoint=xBot+(int)((((this.data[kk][ii])-xLow)/xdenom)*xLen); + ynewpoint=yBot-(int)((((this.data[kk+1][ii])-yLow)/ydenom)*yLen); + lengths[ii-1] = (int)Fmath.hypot((double)(xnewpoint-xoldpoint), (double)(ynewpoint-yoldpoint)); + totalLength += lengths[ii-1]; + gradients[ii-1] = (double)(ynewpoint-yoldpoint)/(double)(xnewpoint-xoldpoint); + intercepts[ii-1] = (double)yoldpoint - gradients[ii-1]*xoldpoint; + xoldpoint=xnewpoint; + yoldpoint=ynewpoint; + } + + // number of points + int incrmt = totalLength/(4*niPoints-1); + int nlpointsold = 0; + int nlpointsnew = 0; + int totalLpoints = 1; + for(int ii=1; ii<nxpoints; ii++){ + totalLpoints++; + nlpointsnew = lengths[ii-1]/incrmt; + for(int jj = nlpointsold+1; jj<(nlpointsnew + nlpointsold); jj++)totalLpoints ++; + nlpointsold = nlpointsold + nlpointsnew; + } + + // fill arrays + int[] xdashed = new int[totalLpoints]; + int[] ydashed = new int[totalLpoints]; + nlpointsold = 0; + nlpointsnew = 0; + xdashed[0] = xBot+(int)((((this.data[kk][0])-xLow)/xdenom)*xLen); + ydashed[0] = yBot-(int)((((this.data[kk+1][0])-yLow)/ydenom)*yLen); + for(int ii=1; ii<nxpoints; ii++){ + nlpointsnew = lengths[ii-1]/incrmt; + xdashed[nlpointsnew + nlpointsold] = xBot+(int)((((this.data[kk][ii])-xLow)/xdenom)*xLen); + ydashed[nlpointsnew + nlpointsold] = yBot-(int)((((this.data[kk+1][ii])-yLow)/ydenom)*yLen); + if(Math.abs(gradients[ii-1])>0.5){ + int diff = (ydashed[nlpointsnew + nlpointsold] - ydashed[nlpointsold])/nlpointsnew; + for(int jj = nlpointsold+1; jj<(nlpointsnew + nlpointsold); jj++){ + ydashed[jj] = ydashed[jj-1]+diff; + if(Fmath.isInfinity(Math.abs(gradients[ii-1]))){ + xdashed[jj] = xdashed[nlpointsnew + nlpointsold]; + } + else{ + xdashed[jj] = (int)(((double)ydashed[jj] - intercepts[ii-1])/gradients[ii-1]); + } + } + } + else{ + int diff = (xdashed[nlpointsnew + nlpointsold] - xdashed[nlpointsold])/nlpointsnew; + for(int jj = nlpointsold+1; jj<(nlpointsnew + nlpointsold); jj++){ + xdashed[jj] = xdashed[jj-1]+diff; + ydashed[jj] = (int)(gradients[ii-1]*ydashed[jj] + intercepts[ii-1]); + } + } + nlpointsold = nlpointsold + nlpointsnew; + } + + dsum=0; + dcheck=true; + for(int ii=1; ii<totalLpoints; ii++){ + dsum++; + if(dsum>dashLength[i]){ + dsum=0; + if(dcheck){ + dcheck=false; + } + else{ + dcheck=true; + } + } + if(dcheck)g.drawLine(xdashed[ii-1],ydashed[ii-1],xdashed[ii],ydashed[ii]); + } + } + + + + // Plot points + if(pointOpt[i]>0){ + for(int ii=0; ii<nxpoints; ii++){ + ps=this.pointSize[i]; + psh=ps/2; + xxp=xBot+(int)(((this.data[kk][ii]-xLow)/xdenom)*xLen); + yyp=yBot-(int)(((this.data[kk+1][ii]-yLow)/ydenom)*yLen); + switch(pointOpt[i]){ + case 1: g.drawOval(xxp-psh, yyp-psh, ps, ps); + break; + case 2: g.drawRect(xxp-psh, yyp-psh, ps, ps); + break; + case 3: g.drawLine(xxp-psh, yyp, xxp, yyp+psh); + g.drawLine(xxp, yyp+psh, xxp+psh, yyp); + g.drawLine(xxp+psh, yyp, xxp, yyp-psh); + g.drawLine(xxp, yyp-psh, xxp-psh, yyp); + break; + case 4: g.fillOval(xxp-psh, yyp-psh, ps, ps); + break; + case 5: g.fillRect(xxp-psh, yyp-psh, ps, ps); + break; + case 6: for(int jj=0; jj<psh; jj++)g.drawLine(xxp-jj, yyp-psh+jj, xxp+jj, yyp-psh+jj); + for(int jj=0; jj<=psh; jj++)g.drawLine(xxp-psh+jj, yyp+jj, xxp+psh-jj, yyp+jj); + break; + case 7: g.drawLine(xxp-psh, yyp-psh, xxp+psh, yyp+psh); + g.drawLine(xxp-psh, yyp+psh, xxp+psh, yyp-psh); + break; + case 8: g.drawLine(xxp-psh, yyp, xxp+psh, yyp); + g.drawLine(xxp, yyp+psh, xxp, yyp-psh); + break; + default:g.drawLine(xxp-psh, yyp-psh, xxp+psh, yyp+psh); + g.drawLine(xxp-psh, yyp+psh, xxp+psh, yyp-psh); + break; + } + + if(this.errorBar[i]){ + yype=yBot-(int)(((errors[i][ii]-yLow)/ydenom)*yLen); + g.drawLine(xxp, yyp, xxp, yype); + g.drawLine(xxp-4, yype, xxp+4, yype); + yype=2*yyp-yype; + g.drawLine(xxp, yyp, xxp, yype); + g.drawLine(xxp-4, yype, xxp+4, yype); + } + } + } + kk+=2; + } + } + + // Return the serial version unique identifier + public static long getSerialVersionUID(){ + return Plot.serialVersionUID; + } +} diff --git a/src/main/java/flanagan/plot/PlotGraph.java b/src/main/java/flanagan/plot/PlotGraph.java new file mode 100755 index 0000000000000000000000000000000000000000..dd0b5d437d58ddf3317a86069b794d370ac17b18 --- /dev/null +++ b/src/main/java/flanagan/plot/PlotGraph.java @@ -0,0 +1,183 @@ +/* +* Class PlotGraph +* +* A class that creates a window and displays within that window +* a graph of one or more x-y data sets +* +* This class extends Plot (also from Michael Thomas Flanagan's Library) +* +* For use if you are incorporating a plot into your own Java program +* See Plotter for a free standing graph plotting application +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: February 2002 +* UPDATED: 22 April 2004 and 14 August 2004, 7 July 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/PlotGraph.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2002 - 2008 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.plot; + +// Include the windowing libraries +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.JFrame; +import java.io.Serializable; + +// Declare a class that creates a window capable of being drawn to +public class PlotGraph extends Plot implements Serializable{ + + protected static final long serialVersionUID = 1L; // serial version unique identifier + + protected int graphWidth = 800; // width of the window for the graph in pixels + protected int graphHeight = 600; // height of the window for the graph in pixels + protected int closeChoice = 1; // =1 clicking on close icon causes window to close + // and the the program is exited. + // =2 clicking on close icon causes window to close + // leaving the program running. + // Create the window object + protected JFrame window = new JFrame("Michael T Flanagan's plotting program - PlotGraph"); + + // Constructor + // One 2-dimensional data arrays + public PlotGraph(double[][] data){ + super(data); + } + + // Constructor + //Two 1-dimensional data arrays + public PlotGraph(double[] xData, double[] yData){ + super(xData, yData); + } + + // Rescale the y dimension of the graph window and graph + public void rescaleY(double yScaleFactor) + { + this.graphHeight=(int)Math.round((double)graphHeight*yScaleFactor); + super.yLen=(int)Math.round((double)super.yLen*yScaleFactor); + super.yTop=(int)Math.round((double)super.yTop*yScaleFactor); + super.yBot=super.yTop + super.yLen; + } + + // Rescale the x dimension of the graph window and graph + public void rescaleX(double xScaleFactor) + { + this.graphWidth=(int)Math.round((double)graphWidth*xScaleFactor); + super.xLen=(int)Math.round((double)super.xLen*xScaleFactor); + super.xBot=(int)Math.round((double)super.xBot*xScaleFactor); + super.xTop=super.xBot + super.xLen; + } + + // Get pixel width of the PlotGraph window + public int getGraphWidth(){ + return this.graphWidth; + } + + // Get pixel height of the PlotGraph window + public int getGraphHeight(){ + return this.graphHeight; + } + + // Reset height of graph window (pixels) + public void setGraphHeight(int graphHeight){ + this.graphHeight=graphHeight; + } + + // Reset width of graph window (pixels) + public void setGraphWidth(int graphWidth){ + this.graphWidth=graphWidth; + } + + // Get close choice + public int getCloseChoice(){ + return this.closeChoice; + } + + // Reset close choice + public void setCloseChoice(int choice){ + this.closeChoice = choice; + } + + // The paint method to draw the graph. + public void paint(Graphics g){ + + // Rescale - needed for redrawing if graph window is resized by dragging + double newGraphWidth = this.getSize().width; + double newGraphHeight = this.getSize().height; + double xScale = newGraphWidth/(double)this.graphWidth; + double yScale = newGraphHeight/(double)this.graphHeight; + rescaleX(xScale); + rescaleY(yScale); + + // Call graphing method + graph(g); + } + + // Set up the window and show graph + public void plot(){ + // Set the initial size of the graph window + setSize(this.graphWidth, this.graphHeight); + + // Set background colour + window.getContentPane().setBackground(Color.white); + + // Choose close box + if(this.closeChoice==1){ + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + else{ + window.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + } + + // Add graph canvas + window.getContentPane().add("Center", this); + + // Set the window up + window.pack(); + window.setResizable(true); + window.toFront(); + + // Show the window + window.setVisible(true); + } + + // Displays dialogue box asking if you wish to exit program + // Answering yes end program - will simultaneously close the graph windows + public void endProgram(){ + + int ans = JOptionPane.showConfirmDialog(null, "Do you wish to end the program\n"+"This will also close the graph window or windows", "End Program", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if(ans==0){ + System.exit(0); + } + else{ + String message = "Now you must press the appropriate escape key/s, e.g. Ctrl C, to exit this program\n"; + if(this.closeChoice==1)message += "or close a graph window"; + JOptionPane.showMessageDialog(null, message); + } + } + + // Return the serial version unique identifier + public static long getSerialVersionUID(){ + return PlotGraph.serialVersionUID; + } + +} + diff --git a/src/main/java/flanagan/plot/PlotPoleZero.java b/src/main/java/flanagan/plot/PlotPoleZero.java new file mode 100755 index 0000000000000000000000000000000000000000..ba600f43ae82e1f89b5e6dc5c622a58a39f82394 --- /dev/null +++ b/src/main/java/flanagan/plot/PlotPoleZero.java @@ -0,0 +1,792 @@ +/* +* Class PlotPoleZero +* +* Plots, in a window, the poles and zeros of a transfer function, +* of the form of a polynomial over a polynomial, in either the s- or +* z-plane given the coefficients of the polynomials either as two arrays +* or as two types ComplexPolynom() +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: July 2002 +* REVISED: 22 June 2003, 14 August 2004, 16 May 2005, 7 July 2008, 10-12 August 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/PlotPoleZero.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) June 2002 - 2008 +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + + +package flanagan.plot; + +import java.awt.*; + +import flanagan.math.Fmath; +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; +import flanagan.io.*; + +public class PlotPoleZero{ + private ComplexPoly numerPoly = null; // ComplexPoly instance of the numerator polynomial + private ComplexPoly denomPoly = null; // ComplexPoly instance of the denominator polynomial + private Complex[] numerRoots = null; // Roots of the numerator polynomial + private Complex[] denomRoots = null; // Roots of the denominator polynomial + private double[][] data = null; // Data for PlotGraph + private int nDeg = 0; // degree of numerator polynomial + private int dDeg = 0; // degree of denominator polynomial + private int mDeg = 0; // maximum of the two polynomial degrees + private int sORz = 0; // if 0 s or z plot, =1 s plane plot, =2 z plane plot + private boolean zerosSet = false; // = true if zeros entered directly + private boolean polesSet = false; // = true if poles entered directly + private boolean zCircle = false; // if true - a unit radius circle is plotted + private boolean noImag = true; // if true - no imaginary non-zero values + private boolean noReal = true; // if true - no real non-zero values + private boolean noZeros = true; // = true if no zeros, false if there are + private boolean noPoles = true; // = true if no poles, false if there are + private boolean setUnitAxes = false; // if true - axis set to span at least -1 to +1 + // and unit circle is drawn + private boolean setEqualAxes = false; // if true - axis set to span equal ranges + private double scaleFactor = 1.0; // scales all dimensions of the plot + + + // Constructors + // no poles or zeros set + public PlotPoleZero(){ + } + + // numer Array of coefficients of the numerator polynomial + // denom Array of coefficients of the denominator polynomial + // ComplexPoly coefficients + public PlotPoleZero(ComplexPoly numer, ComplexPoly denom){ + + if(numer!=null){ + this.nDeg = numer.getDeg(); + if(this.nDeg>0){ + this.numerPoly = ComplexPoly.copy(numer); + this.numerRoots = Complex.oneDarray(nDeg); + this.mDeg = nDeg; + this.noZeros = false; + } + } + + if(denom!=null){ + this.dDeg = denom.getDeg(); + if(this.dDeg>0){ + this.denomPoly = ComplexPoly.copy(denom); + this.denomRoots = Complex.oneDarray(dDeg); + if(!this.noZeros){ + this.mDeg = Math.max(nDeg, dDeg); + } + else{ + this.mDeg = dDeg; + } + this.noPoles = false; + } + } + if(this.noZeros && this.noPoles)throw new IllegalArgumentException("No poles or zeros entered"); + } + + // Two arrays of Complex coefficients + public PlotPoleZero(Complex[] numer, Complex[] denom){ + + if(numer!=null){ + this.nDeg = numer.length-1; + if(this.nDeg>0){ + this.numerPoly = new ComplexPoly(numer);; + this.numerRoots = Complex.oneDarray(nDeg); + this.mDeg = nDeg; + this.noZeros = false; + } + } + + if(denom!=null){ + this.dDeg = denom.length-1; + if(this.dDeg>0){ + this.denomPoly = new ComplexPoly(denom);; + this.denomRoots = Complex.oneDarray(dDeg); + if(!this.noZeros){ + this.mDeg = Math.max(nDeg, dDeg); + } + else{ + this.mDeg = dDeg; + } + this.noPoles = false; + } + if(this.noZeros && this.noPoles)throw new IllegalArgumentException("No poles or zeros entered"); + } + } + + + // Two arrays of double coefficients + public PlotPoleZero(double[] numer, double[] denom){ + + if(numer!=null){ + this.nDeg = numer.length-1; + if(this.nDeg>0){ + this.numerPoly = new ComplexPoly(numer);; + this.numerRoots = Complex.oneDarray(nDeg); + this.mDeg = nDeg; + this.noZeros = false; + } + } + + if(denom!=null){ + this.dDeg = denom.length-1; + if(this.dDeg>0){ + this.denomPoly = new ComplexPoly(denom);; + this.denomRoots = Complex.oneDarray(dDeg); + if(!this.noZeros){ + this.mDeg = Math.max(nDeg, dDeg); + } + else{ + this.mDeg = dDeg; + } + this.noPoles = false; + } + if(this.noZeros && this.noPoles)throw new IllegalArgumentException("No poles or zeros entered"); + } + } + + + // Enter zeros as ComplexPoly + public void setNumerator(ComplexPoly numer){ + if(numer!=null){ + this.nDeg = numer.getDeg(); + if(this.nDeg>0){ + this.numerPoly = ComplexPoly.copy(numer); + this.numerRoots = Complex.oneDarray(nDeg); + if(!this.noPoles){ + this.mDeg = Math.max(nDeg, dDeg); + } + else{ + this.mDeg = nDeg; + } + this.noZeros = false; + } + } + else{ + this.noZeros = true; + } + } + + + // Enter zeros: array of Complex coefficients + public void setNumerator(Complex[] numer){ + if(numer!=null){ + this.nDeg = numer.length-1; + if(this.nDeg>0){ + this.numerPoly = new ComplexPoly(numer);; + this.numerRoots = Complex.oneDarray(nDeg); + if(!this.noPoles){ + this.mDeg = Math.max(nDeg, dDeg); + } + else{ + this.mDeg = nDeg; + } + this.noZeros = false; + } + } + else{ + this.noZeros = true; + } + } + + // Enter zeros: array of double coefficients + public void setNumerator(double[] numer){ + if(numer!=null){ + this.nDeg = numer.length-1; + if(this.nDeg>0){ + this.numerPoly = new ComplexPoly(numer);; + this.numerRoots = Complex.oneDarray(nDeg); + if(!this.noPoles){ + this.mDeg = Math.max(nDeg, dDeg); + } + else{ + this.mDeg = nDeg; + } + this.noZeros = false; + } + } + else{ + this.noZeros = true; + } + } + + // Enter zeros as Complex roots + public void setZeros(Complex[] zeros){ + if(zeros!=null){ + this.nDeg = zeros.length; + if(this.nDeg>0){ + this.numerRoots = zeros; + this.numerPoly = ComplexPoly.rootsToPoly(zeros); + if(!this.noPoles){ + this.mDeg = Math.max(nDeg, dDeg); + } + else{ + this.mDeg = nDeg; + } + this.noZeros = false; + } + this.zerosSet = true; + } + else{ + this.noZeros = true; + } + } + + // Enter zeros as double roots + public void setZeros(double[] zeros){ + int n = zeros.length; + Complex[] czeros = Complex.oneDarray(n); + for(int i=0; i<n; i++)czeros[i] = new Complex(zeros[i], 0.0); + this.setZeros(czeros); + } + + + + // Enter poles as ComplexPoly + public void setDenominator(ComplexPoly denom){ + if(denom!=null){ + this.dDeg = denom.getDeg(); + if(this.dDeg>0){ + this.denomPoly = ComplexPoly.copy(denom); + this.denomRoots = Complex.oneDarray(dDeg); + if(!this.noZeros){ + this.mDeg = Math.max(nDeg, dDeg); + } + else{ + this.mDeg = dDeg; + } + this.noPoles = false; + } + } + else{ + this.noPoles = true; + } + } + + + + // Enter poles: array of Complex coefficients + public void setDenominator(Complex[] denom){ + if(denom!=null){ + this.dDeg = denom.length-1; + if(this.dDeg>0){ + this.denomPoly = new ComplexPoly(denom);; + this.denomRoots = Complex.oneDarray(dDeg); + if(!this.noZeros){ + this.mDeg = Math.max(nDeg, dDeg); + } + else{ + this.mDeg = dDeg; + } + this.noPoles = false; + } + } + else{ + this.noPoles = true; + } + } + + + + // Enter poles: array of double coefficients + public void setDenominator(double[] denom){ + if(denom!=null){ + this.dDeg = denom.length-1; + if(this.dDeg>0){ + this.denomPoly = new ComplexPoly(denom);; + this.denomRoots = Complex.oneDarray(dDeg); + if(!this.noZeros){ + this.mDeg = Math.max(nDeg, dDeg); + } + else{ + this.mDeg = dDeg; + } + this.noPoles = false; + } + } + else{ + this.noPoles = true; + } + } + + // Enter poles as Complex roots + public void setPoles(Complex[] poles){ + if(poles!=null){ + this.dDeg = poles.length; + if(this.dDeg>0){ + this.denomRoots = poles; + this.denomPoly = ComplexPoly.rootsToPoly(poles); + if(!this.noZeros){ + this.mDeg = Math.max(nDeg, dDeg); + } + else{ + this.mDeg = dDeg; + } + this.noPoles = false; + } + this.polesSet = true; + } + else{ + this.noPoles = true; + } + } + + // Enter poles as double roots + public void setPoles(double[] poles){ + int n = poles.length; + Complex[] cpoles = Complex.oneDarray(n); + for(int i=0; i<n; i++)cpoles[i] = new Complex(poles[i], 0.0); + this.setPoles(cpoles); + } + + + // Sets overall scale factor + public void setScaleFactor(double scale){ + this.scaleFactor = scale; + } + + // Sets plot to s-plane plot + public void setS(){ + this.sORz=1; + } + + // Sets plot to z-plane plot + public void setZ(){ + this.sORz=2; + this.zCircle=true; + } + + // set axes to span unit circle + public void setUnitAxes(){ + this.setUnitAxes = true; + this.setEqualAxes = false; + } + + // Sets axes to span equal ranges + public void setEqualAxes(){ + this.setEqualAxes = true; + this.setUnitAxes = false; + } + + // Sets plot a unit radius circle. + public void setCircle(){ + this.zCircle=true; + if(this.sORz!=2)sORz=2; + } + + // Unsets plot a unit radius circle. + public void unsetCircle(){ + this.zCircle=false; + } + + // Calculate roots and plot and write to text file + // Plot title given + public Complex[][] pzPlot(String title){ + if(this.noPoles && this.noZeros)throw new IllegalArgumentException("No poles or zeros have been entered"); + + double absReal = 0.0D; + double absImag = 0.0D; + double zeroLimit = 1e-5; + double minall = 0.0; + double maxall = 0.0; + int ncirc = 600; + double stp = 2.0/(double)(ncirc-1); + int maxPoints = 0; + double[] zerosReal = null; + double[] zerosImag = null; + double[] polesReal = null; + double[] polesImag = null; + double[] xAxisIfRealZero = null; + double[] yAxisIfRealZero = null; + double[] xAxisIfImagZero = null; + double[] yAxisIfImagZero = null; + double[] xAxisCircle1 = new double[ncirc]; + double[] yAxisCircle1 = new double[ncirc]; + double[] xAxisCircle2 = new double[ncirc]; + double[] yAxisCircle2 = new double[ncirc]; + + Complex[][] zerosAndPoles = {null, null}; + + int mm=0; + if(this.nDeg>0){ + mm++; + zerosReal = new double[this.nDeg]; + zerosImag = new double[this.nDeg]; + if(!this.zerosSet)this.numerRoots = this.numerPoly.roots(); + zerosAndPoles[0] = this.numerRoots; + for(int i=0; i<this.nDeg; i++){ + zerosReal[i] = this.numerRoots[i].getReal(); + zerosImag[i] = this.numerRoots[i].getImag(); + if(!numerRoots[i].isZero()){ + absReal = Math.abs(zerosReal[i]); + absImag = Math.abs(zerosImag[i]); + if(absReal>absImag){ + if(absImag<zeroLimit*absReal)zerosImag[i]=0.0D; + } + else{ + if(absReal<zeroLimit*absImag)zerosReal[i]=0.0D; + } + } + if(zerosReal[i]!=0.0D)this.noReal=false; + if(zerosImag[i]!=0.0D)this.noImag=false; + } + maxPoints = nDeg; + } + + if(this.dDeg>0){ + mm++; + polesReal = new double[this.dDeg]; + polesImag = new double[this.dDeg]; + if(!this.polesSet)this.denomRoots = this.denomPoly.roots(); + zerosAndPoles[1] = this.denomRoots; + for(int i=0; i<this.dDeg; i++){ + polesReal[i] = this.denomRoots[i].getReal(); + polesImag[i] = this.denomRoots[i].getImag(); + if(!denomRoots[i].isZero()){ + absReal = Math.abs(polesReal[i]); + absImag = Math.abs(polesImag[i]); + if(absReal>absImag){ + if(absImag<zeroLimit*absReal)polesImag[i]=0.0D; + } + else{ + if(absReal<zeroLimit*absImag)polesReal[i]=0.0D; + } + } + if(polesReal[i]!=0.0D)this.noReal=false; + if(polesImag[i]!=0.0D)this.noImag=false; + } + if(dDeg>maxPoints)maxPoints=dDeg; + } + + if(this.noReal){ + mm++; + xAxisIfRealZero = new double[2]; + xAxisIfRealZero[0]=1.D; + xAxisIfRealZero[1]=-1.0D; + yAxisIfRealZero = new double[2]; + yAxisIfRealZero[0]=0.0D; + yAxisIfRealZero[1]=0.0D; + if(2>maxPoints)maxPoints=2; + } + + if(this.noImag){ + mm++; + xAxisIfImagZero = new double[2]; + xAxisIfImagZero[0]=0.0D; + xAxisIfImagZero[1]=0.0D; + yAxisIfImagZero = new double[2]; + yAxisIfImagZero[0]=1.0D; + yAxisIfImagZero[1]=-1.0D; + if(2>maxPoints)maxPoints=2; + } + + if(this.zCircle){ + mm+=2; + xAxisCircle1[0]=-1.0; + yAxisCircle1[0]=0.0; + xAxisCircle2[0]=-1.0; + yAxisCircle2[0]=0.0; + for(int i=1; i<ncirc; i++){ + xAxisCircle1[i]=xAxisCircle1[i-1]+stp; + yAxisCircle1[i]=Math.sqrt(1.0-xAxisCircle1[i]*xAxisCircle1[i]); + xAxisCircle2[i]=xAxisCircle2[i-1]+stp; + yAxisCircle2[i]=-yAxisCircle1[i]; + } + if(ncirc>maxPoints)maxPoints=ncirc; + } + + if(this.setEqualAxes){ + mm++; + double maxpr = Fmath.maximum(polesReal); + double maxzr = Fmath.maximum(zerosReal); + double maxr = Math.max(maxpr, maxzr); + double maxpi = Fmath.maximum(polesImag); + double maxzi = Fmath.maximum(zerosImag); + double maxi = Math.max(maxpi, maxzi); + maxall = Math.max(maxr, maxi); + + double minpr = Fmath.minimum(polesReal); + double minzr = Fmath.minimum(zerosReal); + double minr = Math.min(minpr, minzr); + double minpi = Fmath.minimum(polesImag); + double minzi = Fmath.minimum(zerosImag); + double mini = Math.min(minpi, minzi); + minall = Math.min(minr, mini); + } + + int ii = 0; + + // Create array for data to be plotted + double[][] data = PlotGraph.data(mm, maxPoints); + boolean[] trim = new boolean[mm]; + boolean[] minmax = new boolean[mm]; + int[] line = new int[mm]; + int[] point = new int[mm]; + + // Fill above array with data to be plotted + ii=0; + if(this.nDeg>0){ + line[ii]=0; + point[ii]=1; + trim[ii]=false; + minmax[ii]=true; + for(int i=0; i<nDeg; i++){ + data[2*ii][i]=zerosReal[i]; + data[2*ii+1][i]=zerosImag[i]; + } + ii++; + } + if(this.dDeg>0){ + line[ii]=0; + point[ii]=7; + trim[ii]=false; + minmax[ii]=true; + for(int i=0; i<dDeg; i++){ + data[2*ii][i]=polesReal[i]; + data[2*ii+1][i]=polesImag[i]; + } + ii++; + } + if(this.zCircle){ + line[ii]=3; + point[ii]=0; + trim[ii]=true; + minmax[ii]=false; + if(this.setUnitAxes)minmax[ii]=true; + for(int i=0; i<ncirc; i++){ + data[2*ii][i]=xAxisCircle1[i]; + data[2*ii+1][i]=yAxisCircle1[i]; + } + + ii++; + line[ii]=3; + point[ii]=0; + trim[ii]=true; + minmax[ii]=false; + if(this.setUnitAxes)minmax[ii]=true; + for(int i=0; i<ncirc; i++){ + data[2*ii][i]=xAxisCircle2[i]; + data[2*ii+1][i]=yAxisCircle2[i]; + } + ii++; + } + if(this.noReal){ + line[ii]=0; + point[ii]=0; + trim[ii]=false; + minmax[ii]=true; + for(int i=0; i<2; i++){ + data[2*ii][i]=xAxisIfRealZero[i]; + data[2*ii+1][i]=yAxisIfRealZero[i]; + } + ii++; + } + if(this.noImag){ + line[ii]=0; + point[ii]=0; + trim[ii]=false; + minmax[ii]=true; + + for(int i=0; i<2; i++){ + data[2*ii][i]=xAxisIfImagZero[i]; + data[2*ii+1][i]=yAxisIfImagZero[i]; + } + ii++; + } + if(this.setEqualAxes){ + line[ii]=0; + point[ii]=0; + trim[ii]=false; + minmax[ii]=true; + + data[2*ii][0]=minall; + data[2*ii+1][0]=minall; + data[2*ii][1]=maxall; + data[2*ii+1][1]=maxall; + ii++; + } + + // Create an instance of PlotGraph with above data + PlotGraph pg = new PlotGraph(data); + pg.setLine(line); + pg.setPoint(point); + pg.setTrimOpt(trim); + pg.setMinMaxOpt(minmax); + pg.setXlowFac(0.0D); + pg.setYlowFac(0.0D); + pg.setGraphWidth((int)(this.scaleFactor*760.0)); + pg.setGraphHeight((int)(this.scaleFactor*700.0)); + pg.setXaxisLen((int)(this.scaleFactor*560.0)); + pg.setYaxisLen((int)(this.scaleFactor*560.0)); + pg.setYhigh((int)(this.scaleFactor*80.0)); + pg.setNoOffset(true); + + switch(sORz){ + case 0: + pg.setGraphTitle("Pole Zero Plot: "+title); + pg.setXaxisLegend("Real part of s or z"); + pg.setYaxisLegend("Imaginary part of s or z"); + break; + case 1: + pg.setGraphTitle("Pole Zero Plot (s-plane): "+title); + pg.setXaxisLegend("Real part of s"); + pg.setYaxisLegend("Imaginary part of s"); + break; + case 2: + pg.setGraphTitle("Pole Zero Plot (z-plane): "+title); + pg.setXaxisLegend("Real part of z"); + pg.setYaxisLegend("Imaginary part of z"); + break; + } + + // Plot poles and zeros + pg.plot(); + + // Open and write an output file + + Complex[] numval = null; + Complex[] denval = null; + + FileOutput fout = new FileOutput("PoleZeroOutput.txt"); + + fout.println("Output File for Program PlotPoleZero"); + if(this.sORz==1)fout.println("An s-plane plot"); + if(this.sORz==2)fout.println("A z-plane plot"); + fout.dateAndTimeln(title); + fout.println(); + + if(!this.noZeros){ + numval = numerPoly.polyNomCopy(); + fout.println("Numerator polynomial coefficients"); + for(int i=0;i<=nDeg;i++){ + fout.print(numval[i].toString()); + if(i<nDeg){ + fout.printcomma(); + fout.printsp(); + } + } + fout.println(); + fout.println(); + } + + if(!this.noPoles){ + denval = denomPoly.polyNomCopy(); + fout.println("Denominator polynomial coefficients"); + for(int i=0;i<=dDeg;i++){ + fout.print(denval[i].toString()); + if(i<dDeg){ + fout.printcomma(); + fout.printsp(); + } + } + fout.println(); + fout.println(); + } + + fout.println("Numerator roots (zeros)"); + if(nDeg<1){ + fout.println("No zeros"); + } + else{ + for(int i=0;i<nDeg;i++){ + fout.print(Complex.truncate(numerRoots[i],6)); + if(i<nDeg-1){ + fout.printcomma(); + fout.printsp(); + } + } + fout.println(); + fout.println(); + } + + fout.println("Denominator roots (poles)"); + if(dDeg<1){ + fout.println("No poles"); + } + else{ + for(int i=0;i<dDeg;i++){ + fout.print(Complex.truncate(denomRoots[i],6)); + if(i<dDeg-1){ + fout.printcomma(); + fout.printsp(); + } + } + fout.println(); + fout.println(); + } + + if(this.sORz==2){ + fout.println("Denominator pole radial distances on the z-plane"); + if(dDeg<1){ + fout.println("No poles"); + } + else{ + for(int i=0;i<dDeg;i++){ + fout.print(Fmath.truncate(denomRoots[i].abs(),6)); + if(i<dDeg-1){ + fout.printcomma(); + fout.printsp(); + } + } + } + fout.println(); + fout.println(); + } + + boolean testroots=true; + if(this.sORz==1){ + for(int i=0;i<dDeg;i++){ + if(denomRoots[i].getReal()>0)testroots=false; + } + if(testroots){ + fout.println("All pole real parts are less than or equal to zero - stable system"); + } + else{ + fout.println("At least one pole real part is greater than zero - unstable system"); + } + } + + if(this.sORz==2){ + for(int i=0;i<dDeg;i++){ + if(Fmath.truncate(denomRoots[i].abs(),6)>1.0)testroots=false; + } + if(testroots){ + fout.println("All pole distances from the z-plane zero are less than or equal to one - stable system"); + } + else{ + fout.println("At least one pole distance from the z-plane zero is greater than one - unstable system"); + } + } + + fout.println(); + fout.println("End of file"); + fout.close(); + + return zerosAndPoles; + + } + + // Calculate roots and plot and write to text file + // No plot title given + public Complex[][] pzPlot(){ + String title = "no file title provided"; + return pzPlot(title); + } + +} diff --git a/src/main/java/flanagan/roots/RealRoot.java b/src/main/java/flanagan/roots/RealRoot.java new file mode 100755 index 0000000000000000000000000000000000000000..d9545b2ffcb1d218a5e2d377b1475d7a6d79a3a8 --- /dev/null +++ b/src/main/java/flanagan/roots/RealRoot.java @@ -0,0 +1,1791 @@ +/* +* Class RealRoot +* +* Contains methods for finding a real root +* +* The function whose root is to be determined is supplied +* by means of an interface, RealRootFunction, +* if no derivative required +* +* The function whose root is to be determined is supplied +* by means of an interface, RealRootDerivFunction, +* as is the first derivative if a derivative is required +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 18 May 2003 +* UPDATE: May 2003 - March 2008, 23-24 September 2008 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/RealRoot.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) 2003 - 2008 Michael Thomas Flanagan +* +* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee, +* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies +* and associated documentation or publications. +* +* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions +* and the following disclaimer and requires written permission from the Michael Thomas Flanagan: +* +* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and +* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan: +* +* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose. +* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software +* or its derivatives. +* +***************************************************************************************/ + +package flanagan.roots; + +import java.util.*; +import flanagan.math.Fmath; +import flanagan.complex.Complex; +import flanagan.complex.ComplexPoly; + + +// RealRoot class +public class RealRoot{ + + // INSTANCE VARIABLES + + private double root = Double.NaN; // root to be found + private double tol = 1e-9; // tolerance in determining convergence upon a root + private int iterMax = 3000; // maximum number of iterations allowed in root search + private int iterN = 0; // number of iterations taken in root search + private double upperBound = 0; // upper bound for bisection and false position methods + private double lowerBound = 0; // lower bound for bisection and false position methods + private double estimate = 0; // estimate for Newton-Raphson method + private int maximumBoundsExtension = 100; // number of times that the bounds may be extended + // by the difference separating them if the root is + // found not to be bounded + private boolean noBoundExtensions = false; // = true if number of no extension to the bounds allowed + private boolean noLowerBoundExtensions = false; // = true if number of no extension to the lower bound allowed + private boolean noUpperBoundExtensions = false; // = true if number of no extension to the upper bound allowed + private boolean supressLimitReachedMessage = false; // if true, supresses printing of the iteration limit reached message + private boolean returnNaN = false; // if true exceptions resulting from a bound being NaN do not halt the prorgam but return NaN + // required by PsRandom and Stat classes calling RealRoot + private boolean supressNaNmessage = false; // if = true the bound is NaN root returned as NaN message supressed + + // STATC VARIABLE + + private static int staticIterMax = 3000; // maximum number of iterations allowed in root search (static methods) + + private static int maximumStaticBoundsExtension = 100; // number of times that the bounds may be extended + // by the difference separating them if the root is + // found not to be bounded (static methods) + private static boolean noStaticBoundExtensions = false; // = true if number of no extension to the bounds allowed (static methods) + private static boolean noStaticLowerBoundExtensions = false;// = true if number of no extension to the lower bound allowed (static methods) + private static boolean noStaticUpperBoundExtensions = false;// = true if number of no extension to the upper bound allowed (static methods) + private static boolean staticReturnNaN = false; // if true exceptions resulting from a bound being NaN do not halt the prorgam but return NaN + // required by PsRandom and Stat classes calling RealRoot (static methods) + private static double realTol = 1e-14; // tolerance as imag/real in deciding whether a root is real + + // CONSTRUCTOR + public RealRoot(){ + } + + // INSTANCE METHODS + + // Set lower bound + public void setLowerBound(double lower){ + this.lowerBound = lower; + } + + // Set lower bound + public void setUpperBound(double upper){ + this.upperBound = upper; + } + + // Reset exception handling for NaN bound flag to true + // when flag returnNaN = true exceptions resulting from a bound being NaN do not halt the prorgam but return NaN + // required by PsRandom and Stat classes calling RealRoot + public void resetNaNexceptionToTrue(){ + this.returnNaN = true; + } + + // Reset exception handling for NaN bound flag to false + // when flag returnNaN = false exceptions resulting from a bound being NaN halts the prorgam + // required by PsRandom and Stat classes calling RealRoot + public void resetNaNexceptionToFalse(){ + this.returnNaN = false; + } + + // Supress NaN bound message + // if supressNaNmessage = true the bound is NaN root returned as NaN message supressed + public void supressNaNmessage(){ + this.supressNaNmessage = true; + } + + // Allow NaN bound message + // if supressNaNmessage = false the bound is NaN root returned as NaN message is written + public void allowNaNmessage(){ + this.supressNaNmessage = false; + } + + // Set estimate + public void setEstimate(double estimate){ + this.estimate = estimate; + } + + // Reset the default tolerance + public void setTolerance(double tolerance){ + this.tol=tolerance; + } + + // Get the default tolerance + public double getTolerance(){ + return this.tol; + } + + // Reset the maximum iterations allowed + public void setIterMax(int imax){ + this.iterMax=imax; + } + + // Get the maximum iterations allowed + public int getIterMax(){ + return this.iterMax; + } + + // Get the number of iterations taken + public int getIterN(){ + return this.iterN; + } + + // Reset the maximum number of bounds extensions + public void setmaximumStaticBoundsExtension(int maximumBoundsExtension){ + this.maximumBoundsExtension=maximumBoundsExtension; + } + + // Prevent extensions to the supplied bounds + public void noBoundsExtensions(){ + this.noBoundExtensions = true; + this.noLowerBoundExtensions = true; + this.noUpperBoundExtensions = true; + } + + // Prevent extension to the lower bound + public void noLowerBoundExtension(){ + this.noLowerBoundExtensions = true; + if(this.noUpperBoundExtensions)this.noBoundExtensions = true; + } + + // Prevent extension to the upper bound + public void noUpperBoundExtension(){ + this.noUpperBoundExtensions = true; + if(this.noLowerBoundExtensions)this.noBoundExtensions = true; + } + + // Supresses printing of the iteration limit reached message + // USE WITH CARE - added only to accomadate a specific application using this class!!!!! + public void supressLimitReachedMessage(){ + this.supressLimitReachedMessage = true; + } + + // Combined bisection and Inverse Quadratic Interpolation method + // bounds already entered + public double brent(RealRootFunction g){ + return this.brent(g, this.lowerBound, this.upperBound); + } + + // Combined bisection and Inverse Quadratic Interpolation method + // bounds supplied as arguments + public double brent(RealRootFunction g, double lower, double upper){ + this.lowerBound = lower; + this.upperBound = upper; + + // check upper>lower + if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower"); + + boolean testConv = true; // convergence test: becomes false on convergence + this.iterN = 0; + double temp = 0.0D; + + if(upper<lower){ + temp = upper; + upper = lower; + lower = temp; + } + + // calculate the function value at the estimate of the higher bound to x + double fu = g.function(upper); + // calculate the function value at the estimate of the lower bound of x + double fl = g.function(lower); + if(Double.isNaN(fl)){ + if(this.returnNaN){ + if(!this.supressNaNmessage)System.out.println("Realroot: brent: lower bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("lower bound returned NaN as the function value"); + } + } + if(Double.isNaN(fu)){ + if(this.returnNaN){ + if(!this.supressNaNmessage)System.out.println("Realroot: brent: upper bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("upper bound returned NaN as the function value"); + } + } + + // check that the root has been bounded and extend bounds if not and extension allowed + boolean testBounds = true; + int numberOfBoundsExtension = 0; + double initialBoundsDifference = (upper - lower)/2.0D; + while(testBounds){ + if(fu*fl<=0.0D){ + testBounds=false; + } + else{ + if(this.noBoundExtensions){ + String message = "RealRoot.brent: root not bounded and no extension to bounds allowed\n"; + message += "NaN returned"; + if(!this.supressNaNmessage)System.out.println(message); + return Double.NaN; + } + else{ + numberOfBoundsExtension++; + if(numberOfBoundsExtension>this.maximumBoundsExtension){ + String message = "RealRoot.brent: root not bounded and maximum number of extension to bounds allowed, " + this.maximumBoundsExtension + ", exceeded\n"; + message += "NaN returned"; + if(!this.supressNaNmessage)System.out.println(message); + return Double.NaN; + } + if(!this.noLowerBoundExtensions){ + lower -= initialBoundsDifference; + fl = g.function(lower); + } + if(!this.noUpperBoundExtensions){ + upper += initialBoundsDifference; + fu = g.function(upper); + } + } + } + } + + // check initial values for true root value + if(fl==0.0D){ + this.root=lower; + testConv = false; + } + if(fu==0.0D){ + this.root=upper; + testConv = false; + } + + // Function at mid-point of initial estimates + double mid=(lower+upper)/2.0D; // mid point (bisect) or new x estimate (Inverse Quadratic Interpolation) + double lastMidB = mid; // last succesful mid point + double fm = g.function(mid); + double diff = mid-lower; // difference between successive estimates of the root + double fmB = fm; // last succesful mid value function value + double lastMid=mid; + boolean lastMethod = true; // true; last method = Inverse Quadratic Interpolation, false; last method = bisection method + boolean nextMethod = true; // true; next method = Inverse Quadratic Interpolation, false; next method = bisection method + + // search + double rr=0.0D, ss=0.0D, tt=0.0D, pp=0.0D, qq=0.0D; // interpolation variables + while(testConv){ + // test for convergence + if(fm==0.0D || Math.abs(diff)<this.tol){ + testConv=false; + if(fm==0.0D){ + this.root=lastMid; + } + else{ + if(Math.abs(diff)<this.tol)this.root=mid; + } + } + else{ + lastMethod=nextMethod; + // test for succesfull inverse quadratic interpolation + if(lastMethod){ + if(mid<lower || mid>upper){ + // inverse quadratic interpolation failed + nextMethod=false; + } + else{ + fmB=fm; + lastMidB=mid; + } + } + else{ + nextMethod=true; + } + if(nextMethod){ + // inverse quadratic interpolation + fl=g.function(lower); + fm=g.function(mid); + fu=g.function(upper); + rr=fm/fu; + ss=fm/fl; + tt=fl/fu; + pp=ss*(tt*(rr-tt)*(upper-mid)-(1.0D-rr)*(mid-lower)); + qq=(tt-1.0D)*(rr-1.0D)*(ss-1.0D); + lastMid=mid; + diff=pp/qq; + mid=mid+diff; + } + else{ + // Bisection procedure + fm=fmB; + mid=lastMidB; + if(fm*fl>0.0D){ + lower=mid; + fl=fm; + } + else{ + upper=mid; + fu=fm; + } + lastMid=mid; + mid=(lower+upper)/2.0D; + fm=g.function(mid); + diff=mid-lastMid; + fmB=fm; + lastMidB=mid; + } + } + this.iterN++; + if(this.iterN>this.iterMax){ + if(!this.supressLimitReachedMessage){ + if(!this.supressNaNmessage)System.out.println("Class: RealRoot; method: brent; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned"); + if(!this.supressNaNmessage)System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + this.tol); + } + this.root = mid; + testConv = false; + } + } + return this.root; + } + + // bisection method + // bounds already entered + public double bisect(RealRootFunction g){ + return this.bisect(g, this.lowerBound, this.upperBound); + } + + // bisection method + public double bisect(RealRootFunction g, double lower, double upper){ + this.lowerBound = lower; + this.upperBound = upper; + + // check upper>lower + if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower"); + if(upper<lower){ + double temp = upper; + upper = lower; + lower = temp; + } + + boolean testConv = true; // convergence test: becomes false on convergence + this.iterN = 0; // number of iterations + double diff = 1e300; // abs(difference between the last two successive mid-pint x values) + + // calculate the function value at the estimate of the higher bound to x + double fu = g.function(upper); + // calculate the function value at the estimate of the lower bound of x + double fl = g.function(lower); + if(Double.isNaN(fl)){ + if(this.returnNaN){ + if(!this.supressNaNmessage)System.out.println("RealRoot: bisect: lower bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("lower bound returned NaN as the function value"); + } + } + if(Double.isNaN(fu)){ + if(this.returnNaN){ + if(!this.supressNaNmessage)System.out.println("RealRoot: bisect: upper bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("upper bound returned NaN as the function value"); + } + } + // check that the root has been bounded and extend bounds if not and extension allowed + boolean testBounds = true; + int numberOfBoundsExtension = 0; + double initialBoundsDifference = (upper - lower)/2.0D; + while(testBounds){ + if(fu*fl<=0.0D){ + testBounds=false; + } + else{ + if(this.noBoundExtensions){ + String message = "RealRoot.bisect: root not bounded and no extension to bounds allowed\n"; + message += "NaN returned"; + if(!this.supressNaNmessage)System.out.println(message); + return Double.NaN; + + } + else{ + numberOfBoundsExtension++; + if(numberOfBoundsExtension>this.maximumBoundsExtension){ + String message = "RealRoot.bisect: root not bounded and maximum number of extension to bounds allowed, " + this.maximumBoundsExtension + ", exceeded\n"; + message += "NaN returned"; + if(!this.supressNaNmessage)System.out.println(message); + return Double.NaN; + } + if(!this.noLowerBoundExtensions){ + lower -= initialBoundsDifference; + fl = g.function(lower); + } + if(!this.noUpperBoundExtensions){ + upper += initialBoundsDifference; + fu = g.function(upper); + } + } + } + } + + // check initial values for true root value + if(fl==0.0D){ + this.root=lower; + testConv = false; + } + if(fu==0.0D){ + this.root=upper; + testConv = false; + } + + // start search + double mid = (lower+upper)/2.0D; // mid-point + double lastMid = 1e300; // previous mid-point + double fm = g.function(mid); + while(testConv){ + if(fm==0.0D || diff<this.tol){ + testConv=false; + this.root=mid; + } + if(fm*fl>0.0D){ + lower = mid; + fl=fm; + } + else{ + upper = mid; + fu=fm; + } + lastMid = mid; + mid = (lower+upper)/2.0D; + fm = g.function(mid); + diff = Math.abs(mid-lastMid); + this.iterN++; + if(this.iterN>this.iterMax){ + if(!this.supressLimitReachedMessage){ + if(!this.supressNaNmessage)System.out.println("Class: RealRoot; method: bisect; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned"); + if(!this.supressNaNmessage)System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + this.tol); + } + this.root = mid; + testConv = false; + } + } + return this.root; + } + + // false position method + // bounds already entered + public double falsePosition(RealRootFunction g){ + return this.falsePosition(g, this.lowerBound, this.upperBound); + } + + // false position method + public double falsePosition(RealRootFunction g, double lower, double upper){ + this.lowerBound = lower; + this.upperBound = upper; + + // check upper>lower + if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower"); + if(upper<lower){ + double temp = upper; + upper = lower; + lower = temp; + } + + boolean testConv = true; // convergence test: becomes false on convergence + this.iterN = 0; // number of iterations + double diff = 1e300; // abs(difference between the last two successive mid-pint x values) + + // calculate the function value at the estimate of the higher bound to x + double fu = g.function(upper); + // calculate the function value at the estimate of the lower bound of x + double fl = g.function(lower); + if(Double.isNaN(fl)){ + if(this.returnNaN){ + if(!this.supressNaNmessage)System.out.println("RealRoot: fals: ePositionlower bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("lower bound returned NaN as the function value"); + } + } + if(Double.isNaN(fu)){ + if(this.returnNaN){ + if(!this.supressNaNmessage)System.out.println("RealRoot: falsePosition: upper bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("upper bound returned NaN as the function value"); + } + } + + // check that the root has been bounded and extend bounds if not and extension allowed + boolean testBounds = true; + int numberOfBoundsExtension = 0; + double initialBoundsDifference = (upper - lower)/2.0D; + while(testBounds){ + if(fu*fl<=0.0D){ + testBounds=false; + } + else{ + if(this.noBoundExtensions){ + String message = "RealRoot.falsePosition: root not bounded and no extension to bounds allowed\n"; + message += "NaN returned"; + if(!this.supressNaNmessage)System.out.println(message); + return Double.NaN; + } + else{ + numberOfBoundsExtension++; + if(numberOfBoundsExtension>this.maximumBoundsExtension){ + String message = "RealRoot.falsePosition: root not bounded and maximum number of extension to bounds allowed, " + this.maximumBoundsExtension + ", exceeded\n"; + message += "NaN returned"; + if(!this.supressNaNmessage)System.out.println(message); + return Double.NaN; + } + if(!this.noLowerBoundExtensions){ + lower -= initialBoundsDifference; + fl = g.function(lower); + } + if(!this.noUpperBoundExtensions){ + upper += initialBoundsDifference; + fu = g.function(upper); + } + } + } + } + + // check initial values for true root value + if(fl==0.0D){ + this.root=lower; + testConv = false; + } + if(fu==0.0D){ + this.root=upper; + testConv = false; + } + + // start search + double mid = lower+(upper-lower)*Math.abs(fl)/(Math.abs(fl)+Math.abs(fu)); // mid-point + double lastMid = 1e300; // previous mid-point + double fm = g.function(mid); + while(testConv){ + if(fm==0.0D || diff<this.tol){ + testConv=false; + this.root=mid; + } + if(fm*fl>0.0D){ + lower = mid; + fl=fm; + } + else{ + upper = mid; + fu=fm; + } + lastMid = mid; + mid = lower+(upper-lower)*Math.abs(fl)/(Math.abs(fl)+Math.abs(fu)); // mid-point + fm = g.function(mid); + diff = Math.abs(mid-lastMid); + this.iterN++; + if(this.iterN>this.iterMax){ + if(!this.supressLimitReachedMessage){ + if(!this.supressNaNmessage)System.out.println("Class: RealRoot; method: falsePostion; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned"); + if(!this.supressNaNmessage)System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + this.tol); + } + this.root = mid; + testConv = false; + } + } + return this.root; + } + + // Combined bisection and Newton Raphson method + // bounds already entered + public double bisectNewtonRaphson(RealRootDerivFunction g){ + return this.bisectNewtonRaphson(g, this.lowerBound, this.upperBound); + } + + // Combined bisection and Newton Raphson method + // default accuracy used + public double bisectNewtonRaphson(RealRootDerivFunction g, double lower, double upper){ + this.lowerBound = lower; + this.upperBound = upper; + + // check upper>lower + if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower"); + + boolean testConv = true; // convergence test: becomes false on convergence + this.iterN = 0; // number of iterations + double temp = 0.0D; + + if(upper<lower){ + temp = upper; + upper = lower; + lower = temp; + } + + // calculate the function value at the estimate of the higher bound to x + double[] f = g.function(upper); + double fu=f[0]; + // calculate the function value at the estimate of the lower bound of x + f = g.function(lower); + double fl=f[0]; + if(Double.isNaN(fl)){ + if(this.returnNaN){ + if(!this.supressNaNmessage)System.out.println("RealRoot: bisectNewtonRaphson: lower bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("lower bound returned NaN as the function value"); + } + } + if(Double.isNaN(fu)){ + if(this.returnNaN){ + if(!this.supressNaNmessage)System.out.println("RealRoot: bisectNewtonRaphson: upper bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("upper bound returned NaN as the function value"); + } + } + + // check that the root has been bounded and extend bounds if not and extension allowed + boolean testBounds = true; + int numberOfBoundsExtension = 0; + double initialBoundsDifference = (upper - lower)/2.0D; + while(testBounds){ + if(fu*fl<=0.0D){ + testBounds=false; + } + else{ + if(this.noBoundExtensions){ + String message = "RealRoot.bisectNewtonRaphson: root not bounded and no extension to bounds allowed\n"; + message += "NaN returned"; + if(!this.supressNaNmessage)System.out.println(message); + return Double.NaN; + } + else{ + numberOfBoundsExtension++; + if(numberOfBoundsExtension>this.maximumBoundsExtension){ + String message = "RealRoot.bisectNewtonRaphson: root not bounded and maximum number of extension to bounds allowed, " + this.maximumBoundsExtension + ", exceeded\n"; + message += "NaN returned"; + if(!this.supressNaNmessage)System.out.println(message); + return Double.NaN; + } + if(!this.noLowerBoundExtensions){ + lower -= initialBoundsDifference; + f = g.function(lower); + fl = f[0]; + } + if(!this.noUpperBoundExtensions){ + upper += initialBoundsDifference; + f = g.function(upper); + fu = f[0]; + } + } + } + } + + // check initial values for true root value + if(fl==0.0D){ + this.root=lower; + testConv = false; + } + if(fu==0.0D){ + this.root=upper; + testConv = false; + } + + // Function at mid-point of initial estimates + double mid=(lower+upper)/2.0D; // mid point (bisect) or new x estimate (Newton-Raphson) + double lastMidB = mid; // last succesful mid point + f = g.function(mid); + double diff = f[0]/f[1]; // difference between successive estimates of the root + double fm = f[0]; + double fmB = fm; // last succesful mid value function value + double lastMid=mid; + mid = mid-diff; + boolean lastMethod = true; // true; last method = Newton Raphson, false; last method = bisection method + boolean nextMethod = true; // true; next method = Newton Raphson, false; next method = bisection method + + // search + while(testConv){ + // test for convergence + if(fm==0.0D || Math.abs(diff)<this.tol){ + testConv=false; + if(fm==0.0D){ + this.root=lastMid; + } + else{ + if(Math.abs(diff)<this.tol)this.root=mid; + } + } + else{ + lastMethod=nextMethod; + // test for succesfull Newton-Raphson + if(lastMethod){ + if(mid<lower || mid>upper){ + // Newton Raphson failed + nextMethod=false; + } + else{ + fmB=fm; + lastMidB=mid; + } + } + else{ + nextMethod=true; + } + if(nextMethod){ + // Newton-Raphson procedure + f=g.function(mid); + fm=f[0]; + diff=f[0]/f[1]; + lastMid=mid; + mid=mid-diff; + } + else{ + // Bisection procedure + fm=fmB; + mid=lastMidB; + if(fm*fl>0.0D){ + lower=mid; + fl=fm; + } + else{ + upper=mid; + fu=fm; + } + lastMid=mid; + mid=(lower+upper)/2.0D; + f=g.function(mid); + fm=f[0]; + diff=mid-lastMid; + fmB=fm; + lastMidB=mid; + } + } + this.iterN++; + if(this.iterN>this.iterMax){ + if(!this.supressLimitReachedMessage){ + if(!this.supressNaNmessage)System.out.println("Class: RealRoot; method: bisectNewtonRaphson; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned"); + if(!this.supressNaNmessage)System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + this.tol); + } + this.root = mid; + testConv = false; + } + } + return this.root; + } + + // Newton Raphson method + // estimate already entered + public double newtonRaphson(RealRootDerivFunction g){ + return this.newtonRaphson(g, this.estimate); + + } + + // Newton Raphson method + public double newtonRaphson(RealRootDerivFunction g, double x){ + this.estimate = x; + boolean testConv = true; // convergence test: becomes false on convergence + this.iterN = 0; // number of iterations + double diff = 1e300; // difference between the last two successive mid-pint x values + + // calculate the function and derivative value at the initial estimate x + double[] f = g.function(x); + if(Double.isNaN(f[0])){ + if(this.returnNaN){ + if(!this.supressNaNmessage)System.out.println("RealRoot: newtonRaphson: NaN returned as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("NaN returned as the function value"); + } + } + if(Double.isNaN(f[1])){ + if(this.returnNaN){ + if(!this.supressNaNmessage)System.out.println("RealRoot: newtonRaphson: NaN returned as the derivative function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("NaN returned as the derivative function value"); + } + } + + + // search + while(testConv){ + diff = f[0]/f[1]; + if(f[0]==0.0D || Math.abs(diff)<this.tol){ + this.root = x; + testConv=false; + } + else{ + x -= diff; + f = g.function(x); + if(Double.isNaN(f[0]))throw new ArithmeticException("NaN returned as the function value"); + if(Double.isNaN(f[1]))throw new ArithmeticException("NaN returned as the derivative function value"); + if(Double.isNaN(f[0])){ + if(this.returnNaN){ + if(!this.supressNaNmessage)System.out.println("RealRoot: bisect: NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("NaN as the function value"); + } + } + if(Double.isNaN(f[1])){ + if(this.returnNaN){ + if(!this.supressNaNmessage)System.out.println("NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("NaN as the function value"); + } + } + } + this.iterN++; + if(this.iterN>this.iterMax){ + if(!this.supressLimitReachedMessage){ + if(!this.supressNaNmessage)System.out.println("Class: RealRoot; method: newtonRaphson; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(x, 4) + ", returned"); + if(!this.supressNaNmessage)System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + this.tol); + } + this.root = x; + testConv = false; + } + } + return this.root; + } + + // STATIC METHODS + + // Reset the maximum iterations allowed for static methods + public void setStaticIterMax(int imax){ + RealRoot.staticIterMax = imax; + } + + // Get the maximum iterations allowed for static methods + public int getStaticIterMax(){ + return RealRoot.staticIterMax; + } + + // Reset the maximum number of bounds extensions for static methods + public void setStaticMaximumStaticBoundsExtension(int maximumBoundsExtension){ + RealRoot.maximumStaticBoundsExtension = maximumBoundsExtension; + } + + // Prevent extensions to the supplied bounds for static methods + public void noStaticBoundsExtensions(){ + RealRoot.noStaticBoundExtensions = true; + RealRoot.noStaticLowerBoundExtensions = true; + RealRoot.noStaticUpperBoundExtensions = true; + } + + // Prevent extension to the lower bound for static methods + public void noStaticLowerBoundExtension(){ + RealRoot.noStaticLowerBoundExtensions = true; + if(RealRoot.noStaticUpperBoundExtensions)RealRoot.noStaticBoundExtensions = true; + } + + // Prevent extension to the upper bound for static methods + public void noStaticUpperBoundExtension(){ + RealRoot.noStaticUpperBoundExtensions = true; + if(RealRoot.noStaticLowerBoundExtensions)RealRoot.noStaticBoundExtensions = true; + } + + // Reset exception handling for NaN bound flag to true for static methods + // when flag returnNaN = true exceptions resulting from a bound being NaN do not halt the prorgam but return NaN + // required by PsRandom and Stat classes calling RealRoot + public void resetStaticNaNexceptionToTrue(){ + this.staticReturnNaN = true; + } + + // Reset exception handling for NaN bound flag to false for static methods + // when flag returnNaN = false exceptions resulting from a bound being NaN halts the prorgam + // required by PsRandom and Stat classes calling RealRoot + public void resetStaticNaNexceptionToFalse(){ + this.staticReturnNaN= false; + } + + + + + // Combined bisection and Inverse Quadratic Interpolation method + // bounds supplied as arguments + public static double brent(RealRootFunction g, double lower, double upper, double tol){ + // check upper>lower + if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower"); + + double root = Double.NaN; + boolean testConv = true; // convergence test: becomes false on convergence + int iterN = 0; + double temp = 0.0D; + + if(upper<lower){ + temp = upper; + upper = lower; + lower = temp; + } + + // calculate the function value at the estimate of the higher bound to x + double fu = g.function(upper); + // calculate the function value at the estimate of the lower bound of x + double fl = g.function(lower); + if(Double.isNaN(fl)){ + if(RealRoot.staticReturnNaN){ + System.out.println("Realroot: brent: lower bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("lower bound returned NaN as the function value"); + } + } + if(Double.isNaN(fu)){ + if(RealRoot.staticReturnNaN){ + System.out.println("Realroot: brent: upper bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("upper bound returned NaN as the function value"); + } + } + + // check that the root has been bounded and extend bounds if not and extension allowed + boolean testBounds = true; + int numberOfBoundsExtension = 0; + double initialBoundsDifference = (upper - lower)/2.0D; + while(testBounds){ + if(fu*fl<=0.0D){ + testBounds=false; + } + else{ + if(RealRoot.noStaticBoundExtensions){ + String message = "RealRoot.brent: root not bounded and no extension to bounds allowed\n"; + message += "NaN returned"; + System.out.println(message); + return Double.NaN; + } + else{ + numberOfBoundsExtension++; + if(numberOfBoundsExtension>RealRoot.maximumStaticBoundsExtension){ + String message = "RealRoot.brent: root not bounded and maximum number of extension to bounds allowed, " + RealRoot.maximumStaticBoundsExtension + ", exceeded\n"; + message += "NaN returned"; + System.out.println(message); + return Double.NaN; + } + if(!RealRoot.noStaticLowerBoundExtensions){ + lower -= initialBoundsDifference; + fl = g.function(lower); + } + if(!RealRoot.noStaticUpperBoundExtensions){ + upper += initialBoundsDifference; + fu = g.function(upper); + } + } + } + } + + // check initial values for true root value + if(fl==0.0D){ + root=lower; + testConv = false; + } + if(fu==0.0D){ + root=upper; + testConv = false; + } + + // Function at mid-point of initial estimates + double mid=(lower+upper)/2.0D; // mid point (bisect) or new x estimate (Inverse Quadratic Interpolation) + double lastMidB = mid; // last succesful mid point + double fm = g.function(mid); + double diff = mid-lower; // difference between successive estimates of the root + double fmB = fm; // last succesful mid value function value + double lastMid=mid; + boolean lastMethod = true; // true; last method = Inverse Quadratic Interpolation, false; last method = bisection method + boolean nextMethod = true; // true; next method = Inverse Quadratic Interpolation, false; next method = bisection method + + // search + double rr=0.0D, ss=0.0D, tt=0.0D, pp=0.0D, qq=0.0D; // interpolation variables + while(testConv){ + // test for convergence + if(fm==0.0D || Math.abs(diff)<tol){ + testConv=false; + if(fm==0.0D){ + root=lastMid; + } + else{ + if(Math.abs(diff)<tol)root=mid; + } + } + else{ + lastMethod=nextMethod; + // test for succesfull inverse quadratic interpolation + if(lastMethod){ + if(mid<lower || mid>upper){ + // inverse quadratic interpolation failed + nextMethod=false; + } + else{ + fmB=fm; + lastMidB=mid; + } + } + else{ + nextMethod=true; + } + if(nextMethod){ + // inverse quadratic interpolation + fl=g.function(lower); + fm=g.function(mid); + fu=g.function(upper); + rr=fm/fu; + ss=fm/fl; + tt=fl/fu; + pp=ss*(tt*(rr-tt)*(upper-mid)-(1.0D-rr)*(mid-lower)); + qq=(tt-1.0D)*(rr-1.0D)*(ss-1.0D); + lastMid=mid; + diff=pp/qq; + mid=mid+diff; + } + else{ + // Bisection procedure + fm=fmB; + mid=lastMidB; + if(fm*fl>0.0D){ + lower=mid; + fl=fm; + } + else{ + upper=mid; + fu=fm; + } + lastMid=mid; + mid=(lower+upper)/2.0D; + fm=g.function(mid); + diff=mid-lastMid; + fmB=fm; + lastMidB=mid; + } + } + iterN++; + if(iterN>RealRoot.staticIterMax){ + System.out.println("Class: RealRoot; method: brent; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned"); + System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + tol); + root = mid; + testConv = false; + } + } + return root; + } + + + // bisection method + // tolerance supplied + public static double bisect(RealRootFunction g, double lower, double upper, double tol){ + + // check upper>lower + if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower"); + if(upper<lower){ + double temp = upper; + upper = lower; + lower = temp; + } + + double root = Double.NaN; // variable to hold the returned root + boolean testConv = true; // convergence test: becomes false on convergence + int iterN = 0; // number of iterations + double diff = 1e300; // abs(difference between the last two successive mid-pint x values) + + // calculate the function value at the estimate of the higher bound to x + double fu = g.function(upper); + // calculate the function value at the estimate of the lower bound of x + double fl = g.function(lower); + if(Double.isNaN(fl)){ + if(RealRoot.staticReturnNaN){ + System.out.println("RealRoot: bisect: lower bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("lower bound returned NaN as the function value"); + } + } + if(Double.isNaN(fu)){ + if(RealRoot.staticReturnNaN){ + System.out.println("RealRoot: bisect: upper bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("upper bound returned NaN as the function value"); + } + } + // check that the root has been bounded and extend bounds if not and extension allowed + boolean testBounds = true; + int numberOfBoundsExtension = 0; + double initialBoundsDifference = (upper - lower)/2.0D; + while(testBounds){ + if(fu*fl<=0.0D){ + testBounds = false; + } + else{ + if(RealRoot.noStaticBoundExtensions){ + String message = "RealRoot.bisect: root not bounded and no extension to bounds allowed\n"; + message += "NaN returned"; + System.out.println(message); + return Double.NaN; + + } + else{ + numberOfBoundsExtension++; + if(numberOfBoundsExtension>RealRoot.maximumStaticBoundsExtension){ + String message = "RealRoot.bisect: root not bounded and maximum number of extension to bounds allowed, " + RealRoot.maximumStaticBoundsExtension + ", exceeded\n"; + message += "NaN returned"; + System.out.println(message); + return Double.NaN; + } + if(!RealRoot.noStaticLowerBoundExtensions){ + lower -= initialBoundsDifference; + fl = g.function(lower); + } + if(!RealRoot.noStaticUpperBoundExtensions){ + upper += initialBoundsDifference; + fu = g.function(upper); + } + } + } + } + + // check initial values for true root value + if(fl==0.0D){ + root=lower; + testConv = false; + } + if(fu==0.0D){ + root=upper; + testConv = false; + } + + // start search + double mid = (lower+upper)/2.0D; // mid-point + double lastMid = 1e300; // previous mid-point + double fm = g.function(mid); + while(testConv){ + if(fm==0.0D || diff<tol){ + testConv=false; + root=mid; + } + if(fm*fl>0.0D){ + lower = mid; + fl=fm; + } + else{ + upper = mid; + fu=fm; + } + lastMid = mid; + mid = (lower+upper)/2.0D; + fm = g.function(mid); + diff = Math.abs(mid-lastMid); + iterN++; + if(iterN>RealRoot.staticIterMax){ + System.out.println("Class: RealRoot; method: bisect; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned"); + System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + tol); + root = mid; + testConv = false; + } + } + return root; + } + + + + + + + // false position method + // tolerance supplied + public static double falsePosition(RealRootFunction g, double lower, double upper, double tol){ + + // check upper>lower + if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower"); + if(upper<lower){ + double temp = upper; + upper = lower; + lower = temp; + } + + double root = Double.NaN; // variable to hold the returned root + boolean testConv = true; // convergence test: becomes false on convergence + int iterN = 0; // number of iterations + double diff = 1e300; // abs(difference between the last two successive mid-pint x values) + + // calculate the function value at the estimate of the higher bound to x + double fu = g.function(upper); + // calculate the function value at the estimate of the lower bound of x + double fl = g.function(lower); + if(Double.isNaN(fl)){ + if(RealRoot.staticReturnNaN){ + System.out.println("RealRoot: fals: ePositionlower bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("lower bound returned NaN as the function value"); + } + } + if(Double.isNaN(fu)){ + if(RealRoot.staticReturnNaN){ + System.out.println("RealRoot: falsePosition: upper bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("upper bound returned NaN as the function value"); + } + } + + // check that the root has been bounded and extend bounds if not and extension allowed + boolean testBounds = true; + int numberOfBoundsExtension = 0; + double initialBoundsDifference = (upper - lower)/2.0D; + while(testBounds){ + if(fu*fl<=0.0D){ + testBounds=false; + } + else{ + if(RealRoot.noStaticBoundExtensions){ + String message = "RealRoot.falsePosition: root not bounded and no extension to bounds allowed\n"; + message += "NaN returned"; + System.out.println(message); + return Double.NaN; + } + else{ + numberOfBoundsExtension++; + if(numberOfBoundsExtension>RealRoot.maximumStaticBoundsExtension){ + String message = "RealRoot.falsePosition: root not bounded and maximum number of extension to bounds allowed, " + RealRoot.maximumStaticBoundsExtension + ", exceeded\n"; + message += "NaN returned"; + System.out.println(message); + return Double.NaN; + } + if(!RealRoot.noStaticLowerBoundExtensions){ + lower -= initialBoundsDifference; + fl = g.function(lower); + } + if(!RealRoot.noStaticUpperBoundExtensions){ + upper += initialBoundsDifference; + fu = g.function(upper); + } + } + } + } + + // check initial values for true root value + if(fl==0.0D){ + root=lower; + testConv = false; + } + if(fu==0.0D){ + root=upper; + testConv = false; + } + + // start search + double mid = lower+(upper-lower)*Math.abs(fl)/(Math.abs(fl)+Math.abs(fu)); // mid-point + double lastMid = 1e300; // previous mid-point + double fm = g.function(mid); + while(testConv){ + if(fm==0.0D || diff<tol){ + testConv=false; + root=mid; + } + if(fm*fl>0.0D){ + lower = mid; + fl=fm; + } + else{ + upper = mid; + fu=fm; + } + lastMid = mid; + mid = lower+(upper-lower)*Math.abs(fl)/(Math.abs(fl)+Math.abs(fu)); // mid-point + fm = g.function(mid); + diff = Math.abs(mid-lastMid); + iterN++; + if(iterN>RealRoot.staticIterMax){ + System.out.println("Class: RealRoot; method: falsePostion; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned"); + System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + tol); + root = mid; + testConv = false; + } + } + return root; + } + + + + + + + // Combined bisection and Newton Raphson method + // tolerance supplied + public static double bisectNewtonRaphson(RealRootDerivFunction g, double lower, double upper, double tol){ + + // check upper>lower + if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower"); + + double root = Double.NaN; + boolean testConv = true; // convergence test: becomes false on convergence + int iterN = 0; // number of iterations + double temp = 0.0D; + + if(upper<lower){ + temp = upper; + upper = lower; + lower = temp; + } + + // calculate the function value at the estimate of the higher bound to x + double[] f = g.function(upper); + double fu=f[0]; + // calculate the function value at the estimate of the lower bound of x + f = g.function(lower); + double fl=f[0]; + if(Double.isNaN(fl)){ + if(RealRoot.staticReturnNaN){ + System.out.println("RealRoot: bisectNewtonRaphson: lower bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("lower bound returned NaN as the function value"); + } + } + if(Double.isNaN(fu)){ + if(RealRoot.staticReturnNaN){ + System.out.println("RealRoot: bisectNewtonRaphson: upper bound returned NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("upper bound returned NaN as the function value"); + } + } + + // check that the root has been bounded and extend bounds if not and extension allowed + boolean testBounds = true; + int numberOfBoundsExtension = 0; + double initialBoundsDifference = (upper - lower)/2.0D; + while(testBounds){ + if(fu*fl<=0.0D){ + testBounds=false; + } + else{ + if(RealRoot.noStaticBoundExtensions){ + String message = "RealRoot.bisectNewtonRaphson: root not bounded and no extension to bounds allowed\n"; + message += "NaN returned"; + System.out.println(message); + return Double.NaN; + } + else{ + numberOfBoundsExtension++; + if(numberOfBoundsExtension>RealRoot.maximumStaticBoundsExtension){ + String message = "RealRoot.bisectNewtonRaphson: root not bounded and maximum number of extension to bounds allowed, " + RealRoot.maximumStaticBoundsExtension + ", exceeded\n"; + message += "NaN returned"; + System.out.println(message); + return Double.NaN; + } + if(!RealRoot.noStaticLowerBoundExtensions){ + lower -= initialBoundsDifference; + f = g.function(lower); + fl = f[0]; + } + if(!RealRoot.noStaticUpperBoundExtensions){ + upper += initialBoundsDifference; + f = g.function(upper); + fu = f[0]; + } + } + } + } + + // check initial values for true root value + if(fl==0.0D){ + root=lower; + testConv = false; + } + if(fu==0.0D){ + root=upper; + testConv = false; + } + + // Function at mid-point of initial estimates + double mid=(lower+upper)/2.0D; // mid point (bisect) or new x estimate (Newton-Raphson) + double lastMidB = mid; // last succesful mid point + f = g.function(mid); + double diff = f[0]/f[1]; // difference between successive estimates of the root + double fm = f[0]; + double fmB = fm; // last succesful mid value function value + double lastMid=mid; + mid = mid-diff; + boolean lastMethod = true; // true; last method = Newton Raphson, false; last method = bisection method + boolean nextMethod = true; // true; next method = Newton Raphson, false; next method = bisection method + + // search + while(testConv){ + // test for convergence + if(fm==0.0D || Math.abs(diff)<tol){ + testConv=false; + if(fm==0.0D){ + root=lastMid; + } + else{ + if(Math.abs(diff)<tol)root=mid; + } + } + else{ + lastMethod=nextMethod; + // test for succesfull Newton-Raphson + if(lastMethod){ + if(mid<lower || mid>upper){ + // Newton Raphson failed + nextMethod=false; + } + else{ + fmB=fm; + lastMidB=mid; + } + } + else{ + nextMethod=true; + } + if(nextMethod){ + // Newton-Raphson procedure + f=g.function(mid); + fm=f[0]; + diff=f[0]/f[1]; + lastMid=mid; + mid=mid-diff; + } + else{ + // Bisection procedure + fm=fmB; + mid=lastMidB; + if(fm*fl>0.0D){ + lower=mid; + fl=fm; + } + else{ + upper=mid; + fu=fm; + } + lastMid=mid; + mid=(lower+upper)/2.0D; + f=g.function(mid); + fm=f[0]; + diff=mid-lastMid; + fmB=fm; + lastMidB=mid; + } + } + iterN++; + if(iterN>RealRoot.staticIterMax){ + System.out.println("Class: RealRoot; method: bisectNewtonRaphson; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned"); + System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + tol); + root = mid; + testConv = false; + } + } + return root; + } + + + + + + // Newton Raphson method + public static double newtonRaphson(RealRootDerivFunction g, double x, double tol){ + double root = Double.NaN; + boolean testConv = true; // convergence test: becomes false on convergence + int iterN = 0; // number of iterations + double diff = 1e300; // difference between the last two successive mid-pint x values + + // calculate the function and derivative value at the initial estimate x + double[] f = g.function(x); + if(Double.isNaN(f[0])){ + if(RealRoot.staticReturnNaN){ + System.out.println("RealRoot: newtonRaphson: NaN returned as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("NaN returned as the function value"); + } + } + if(Double.isNaN(f[1])){ + if(RealRoot.staticReturnNaN){ + System.out.println("RealRoot: newtonRaphson: NaN returned as the derivative function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("NaN returned as the derivative function value"); + } + } + + + // search + while(testConv){ + diff = f[0]/f[1]; + if(f[0]==0.0D || Math.abs(diff)<tol){ + root = x; + testConv=false; + } + else{ + x -= diff; + f = g.function(x); + if(Double.isNaN(f[0]))throw new ArithmeticException("NaN returned as the function value"); + if(Double.isNaN(f[1]))throw new ArithmeticException("NaN returned as the derivative function value"); + if(Double.isNaN(f[0])){ + if(RealRoot.staticReturnNaN){ + System.out.println("RealRoot: NewtonRaphson: NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("NaN as the function value"); + } + } + if(Double.isNaN(f[1])){ + if(RealRoot.staticReturnNaN){ + System.out.println("NaN as the function value - NaN returned as root"); + return Double.NaN; + } + else{ + throw new ArithmeticException("NaN as the function value"); + } + } + } + iterN++; + if(iterN>RealRoot.staticIterMax){ + System.out.println("Class: RealRoot; method: newtonRaphson; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(x, 4) + ", returned"); + System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + tol); + root = x; + testConv = false; + } + } + return root; + } + + // ROOTS OF A QUADRATIC EQUATION + // c + bx + ax^2 = 0 + // roots returned in root[] + // 4ac << b*b accomodated by these methods + // roots returned as Double in an ArrayList if roots are real + // roots returned as Complex in an ArrayList if any root is complex + public static ArrayList<Object> quadratic(double c, double b, double a){ + + ArrayList<Object> roots = new ArrayList<Object>(2); + + double bsquared = b*b; + double fourac = 4.0*a*c; + if(bsquared<fourac){ + Complex[] croots = ComplexPoly.quadratic(c, b, a); + roots.add("complex"); + roots.add(croots); + } + else{ + double[] droots = new double[2]; + double bsign = Fmath.sign(b); + double qsqrt = Math.sqrt(bsquared - fourac); + qsqrt = -0.5*(b + bsign*qsqrt); + droots[0] = qsqrt/a; + droots[1] = c/qsqrt; + roots.add("real"); + roots.add(droots); + } + return roots; + } + + + // ROOTS OF A CUBIC EQUATION + // a + bx + cx^2 + dx^3 = 0 + // roots returned as Double in an ArrayList if roots are real + // roots returned as Complex in an ArrayList if any root is complex + public static ArrayList<Object> cubic(double a, double b, double c, double d){ + + ArrayList<Object> roots = new ArrayList<Object>(2); + + double aa = c/d; + double bb = b/d; + double cc = a/d; + double bigQ = (aa*aa - 3.0*bb)/9.0; + double bigQcubed = bigQ*bigQ*bigQ; + double bigR = (2.0*aa*aa*aa - 9.0*aa*bb + 27.0*cc)/54.0; + double bigRsquared = bigR*bigR; + + if(bigRsquared>=bigQcubed){ + Complex[] croots = ComplexPoly.cubic(a, b, c, d); + roots.add("complex"); + roots.add(croots); + } + else{ + double[] droots = new double[3]; + double theta = Math.acos(bigR/Math.sqrt(bigQcubed)); + double aover3 = a/3.0; + double qterm = -2.0*Math.sqrt(bigQ); + + droots[0] = qterm*Math.cos(theta/3.0) - aover3; + droots[1] = qterm*Math.cos((theta + 2.0*Math.PI)/3.0) - aover3; + droots[2] = qterm*Math.cos((theta - 2.0*Math.PI)/3.0) - aover3; + roots.add("real"); + roots.add(droots); + } + return roots; + } + + // ROOTS OF A POLYNOMIAL + // For general details of root searching and a discussion of the rounding errors + // see Numerical Recipes, The Art of Scientific Computing + // by W H Press, S A Teukolsky, W T Vetterling & B P Flannery + // Cambridge University Press, http://www.nr.com/ + + // Calculate the roots of a real polynomial + // initial root estimate is zero [for deg>3] + // roots are not olished [for deg>3] + public static ArrayList<Object> polynomial(double[] coeff){ + boolean polish=true; + double estx = 0.0; + return RealRoot.polynomial(coeff, polish, estx); + } + + // Calculate the roots of a real polynomial + // initial root estimate is zero [for deg>3] + // roots are polished [for deg>3] + public static ArrayList<Object> polynomial(double[] coeff, boolean polish){ + double estx = 0.0; + return RealRoot.polynomial (coeff, polish, estx); + } + + // Calculate the roots of a real polynomial + // initial root estimate is estx [for deg>3] + // roots are not polished [for deg>3] + public static ArrayList<Object> polynomial(double[] coeff, double estx){ + boolean polish=true; + return RealRoot.polynomial(coeff, polish, estx); + } + + // Calculate the roots of a real polynomial + // initial root estimate is estx [for deg>3] + // roots are polished [for deg>3] + public static ArrayList<Object> polynomial (double[] coeff, boolean polish, double estx){ + + int nCoeff = coeff.length; + if(nCoeff<2)throw new IllegalArgumentException("a minimum of two coefficients is required"); + ArrayList<Object> roots = new ArrayList<Object>(nCoeff); + boolean realRoots = true; + + // check for zero roots + int nZeros=0; + int ii=0; + boolean testZero=true; + while(testZero){ + if(coeff[ii]==0.0){ + nZeros++; + ii++; + } + else{ + testZero=false; + } + } + + // Repack coefficients + int nCoeffWz = nCoeff - nZeros; + double[] coeffWz = new double[nCoeffWz]; + if(nZeros>0){ + for(int i=0; i<nCoeffWz; i++)coeffWz[i] = coeff[i+nZeros]; + } + else{ + for(int i=0; i<nCoeffWz; i++)coeffWz[i] = coeff[i]; + } + + // Calculate non-zero roots + ArrayList<Object> temp = new ArrayList<Object>(2); + double[] cdreal = null; + switch(nCoeffWz){ + case 0: + case 1: break; + case 2: temp.add("real"); + double[] dtemp = {-coeffWz[0]/coeffWz[1]}; + temp.add(dtemp); + break; + case 3: temp = RealRoot.quadratic(coeffWz[0],coeffWz[1],coeffWz[2]); + if(((String)temp.get(0)).equals("complex"))realRoots = false; + break; + case 4: temp = RealRoot.cubic(coeffWz[0],coeffWz[1],coeffWz[2], coeffWz[3]); + if(((String)temp.get(0)).equals("complex"))realRoots = false; + break; + default: ComplexPoly cp = new ComplexPoly(coeffWz); + Complex[] croots = cp.roots(polish, new Complex(estx, 0.0)); + cdreal = new double[nCoeffWz-1]; + int counter = 0; + for(int i=0; i<(nCoeffWz-1); i++){ + if(croots[i].getImag()/croots[i].getReal()<RealRoot.realTol){ + cdreal[i] = croots[i].getReal(); + counter++; + } + } + if(counter==(nCoeffWz-1)){ + temp.add("real"); + temp.add(cdreal); + } + else{ + temp.add("complex"); + temp.add(croots); + realRoots = false; + } + } + + // Pack roots into returned ArrayList + if(nZeros==0){ + roots = temp; + } + else{ + if(realRoots){ + double[] dtemp1 = new double[nCoeff-1]; + double[] dtemp2 = (double[])temp.get(1); + for(int i=0; i<nCoeffWz-1; i++)dtemp1[i] = dtemp2[i]; + for(int i=0; i<nZeros; i++)dtemp1[i+nCoeffWz-1] = 0.0; + roots.add("real"); + roots.add(dtemp1); + } + else{ + Complex[] dtemp1 = Complex.oneDarray(nCoeff-1); + Complex[] dtemp2 = (Complex[])temp.get(1); + for(int i=0; i<nCoeffWz-1; i++)dtemp1[i] = dtemp2[i]; + for(int i=0; i<nZeros; i++)dtemp1[i+nCoeffWz-1] = new Complex(0.0, 0.0); + roots.add("complex"); + roots.add(dtemp1); + } + } + + return roots; + } + + // Reset the criterion for deciding a that a root, calculated as Complex, is real + // Default option; imag/real <1e-14 + // this method allows thew value of 1e-14 to be reset + public void resetRealTest(double ratio){ + RealRoot.realTol = ratio; + } + +} \ No newline at end of file diff --git a/src/main/java/flanagan/roots/RealRootDerivFunction.java b/src/main/java/flanagan/roots/RealRootDerivFunction.java new file mode 100755 index 0000000000000000000000000000000000000000..0edb45f2ee08d861c7397f97857d76f4af264f60 --- /dev/null +++ b/src/main/java/flanagan/roots/RealRootDerivFunction.java @@ -0,0 +1,41 @@ +/* +* Interface RealRootDerivFunction +* +* The function whose root is to be determined by a class +* RealRoots method, and its first derivative, is supplied +* by means of this interface, RealRootDerivFunction +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 18 May 2003 +* UPDATE: 22 June 2003 +* +* DOCUMENTATION: +* See Michael Thomas Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/RealRoot.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) June 2003 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.roots; + +import java.util.*; +import flanagan.math.Fmath; + +// Interface for RealRoot class +// returns value of function and of the first derivative of the function whose root is required +public interface RealRootDerivFunction{ + double[] function(double x); +} diff --git a/src/main/java/flanagan/roots/RealRootFunction.java b/src/main/java/flanagan/roots/RealRootFunction.java new file mode 100755 index 0000000000000000000000000000000000000000..649c14970873e280ae6d30681038647a9ed9bf40 --- /dev/null +++ b/src/main/java/flanagan/roots/RealRootFunction.java @@ -0,0 +1,42 @@ +/* +* Interface RealRootFunction +* +* The function whose root is to be determined by a class +* RealRoots method, when no first derivative, is supplied +* by means of this interface, RealRootFunction +* +* WRITTEN BY: Dr Michael Thomas Flanagan +* +* DATE: 18 May 2003 +* UPDATE: 22 June 2003 +* +* DOCUMENTATION: +* See Michael T Flanagan's Java library on-line web page: +* http://www.ee.ucl.ac.uk/~mflanaga/java/RealRoot.html +* http://www.ee.ucl.ac.uk/~mflanaga/java/ +* +* Copyright (c) June 2003 Michael Thomas Flanagan +* +* PERMISSION TO COPY: +* Permission to use, copy and modify this software and its documentation for +* NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement +* to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies. +* +* Dr Michael Thomas Flanagan makes no representations about the suitability +* or fitness of the software for any or for a particular purpose. +* Michael Thomas Flanagan shall not be liable for any damages suffered +* as a result of using, modifying or distributing this software or its derivatives. +* +***************************************************************************************/ + +package flanagan.roots; + +import java.util.*; +import flanagan.math.Fmath; + + +// Interface for RealRoot class +// returns value of function whose root is required +public interface RealRootFunction{ + double function(double x); +} diff --git a/src/main/java/plugins/stef/library/FlanaganPlugin.java b/src/main/java/plugins/stef/library/FlanaganPlugin.java index ad7b92d1f87228f727a3cbad7ba704bd7a248b48..f4a2a4d5208b00a146af6855c0e8d1177b93acbe 100644 --- a/src/main/java/plugins/stef/library/FlanaganPlugin.java +++ b/src/main/java/plugins/stef/library/FlanaganPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,9 +18,10 @@ package plugins.stef.library; -import icy.plugin.abstract_.Plugin; -import icy.plugin.interface_.PluginLibrary; +import org.bioimageanalysis.icy.extension.plugin.abstract_.Plugin; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName; -public class FlanaganPlugin extends Plugin implements PluginLibrary { +@IcyPluginName("Flanagan") +public class FlanaganPlugin extends Plugin { // }