├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
├── main
└── java
│ └── org
│ └── orangepalantir
│ ├── filters
│ └── SavitzyGolayFilter.java
│ └── leastsquares
│ ├── Fitter.java
│ ├── Function.java
│ ├── examples
│ └── ParabolaExample.java
│ ├── fitters
│ ├── LinearFitter.java
│ ├── MarquardtFitter.java
│ └── NonLinearSolver.java
│ └── functions
│ ├── ExponentialFunction.java
│ └── LinearFunction.java
└── test
└── java
└── org
└── orangepalantir
└── leastsquares
└── fitters
├── LinearFitterTest.java
├── NonLinearSolverTest.java
└── NonLinearTrigonometricSolver.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # IntelliJ
2 | .idea/
3 | *.iws
4 | *.iml
5 | *.ipr
6 | *.ips
7 | .idea/
8 |
9 |
10 | # Eclipse
11 | .settings/
12 | .metadata/
13 | .classpath
14 | .project
15 |
16 | # Generated
17 | target/
18 | javadoc/
19 | bin/
20 | log/
21 |
22 | # Misc.
23 | .DS_Store
24 | *.bak
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 odinsbane
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | least-squares-in-java
2 | =====================
3 |
4 | Java Least Squares fitting library.
5 | -----------------------------------
6 |
7 | This is a small least squares fitting library made in java.
8 | It was originally used in the development of an image analysis tool
9 | SpeckleTrackerJ. http://athena.physics.lehigh.edu/speckletrackerj/ It uses
10 | methods described in "Numerical Recipes in C", Second Edition (1992).
11 |
12 | The outline of using this library is you have a set of data that you
13 | would like fit a function to. Define the Function, how it evaluates
14 | the input and paramters. Create a Fitter (three types currently) initialized
15 | to the function. Set the fitter with the data and make an initial guess of the
16 | parameters. Tell the fitter to find the best set of parameters which minimizes the
17 | sum of squares of error.
18 |
19 | Example
20 | -------
21 |
22 | Lets say we have some data.
23 |
24 | double[][] xs = {
25 | {0}, {1}, {2}, {3}, {4}, {5}
26 | };
27 | double[] z = {1.1, 0.9, 1.0, 1.35, 1.82, 2.5};
28 |
29 | And we want to fit a quadratic function f(x) = A*x*x + B*x + C. The parameters are A, B, C and the
30 | input is x. So we have 3 parameters and 1 input.
31 |
32 | Function fun = new Function(){
33 | @Override
34 | public double evaluate(double[] values, double[] parameters) {
35 | double A = parameters[0];
36 | double B = parameters[1];
37 | double C = parameters[2];
38 | double x = values[0];
39 | return A*x*x + B*x + C;
40 | }
41 | @Override
42 | public int getNParameters() {
43 | return 3;
44 | }
45 |
46 | @Override
47 | public int getNInputs() {
48 | return 1;
49 | }
50 | };
51 |
52 | The next step is to create a fitter.
53 |
54 | Fitter fit = new LinearFitter(fun);
55 |
56 | Set the data, and make a guess at the initial parameters.
57 |
58 | fit.setData(xs, zs);
59 | fit.setParameters(new double[]{0,0,0});
60 |
61 | fit.fitData();
62 |
63 | The results can be obtained by using getParameters.
64 |
65 | System.out.println(Arrays.toString(fit.getParameters()));
66 | #[0.10000000000000023, -0.20000000000000123, 1.000000000000001]
67 |
68 | This example is included in the examples package.
69 |
70 |
71 | Fitter implementations
72 | ----------------------
73 |
74 | LinearFitter: for use with equations that are linearly dependent on the input parameters. Standard
75 | linear regression where derivatives are taken by setting all of the parameters to zero, except for the
76 | one of interest.
77 |
78 | NonLinearSolver: Similar to the LinearSolver, except it will run multiple iterations, there is a damping
79 | factor, and the derivatives are calculated by taken by varying the parameters a small amount from the
80 | previous guess.
81 |
82 | MarquardtFitter: Similar to the NonLinearSolver except the damping is adaptive.
83 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.orangepalantir
7 | leastsquares
8 | 1.0.1-SNAPSHOT
9 | jar
10 |
11 | Least squares in java.
12 | https://github.com/odinsbane/least-squares-in-java
13 | A small library for using least squres fitting in java. Build using the JAMA
14 | matrix library
15 |
16 |
17 | The MIT License (MIT)
18 | https://opensource.org/licenses/MIT
19 | repo
20 |
21 |
22 |
23 |
24 | odinsbane
25 | Matthew Smith
26 | melkor@orangepalantir.org
27 | https://orangepalantir.org
28 | UCL LMCB
29 | http://ucl.ac.uk/lmcb
30 |
31 | lead
32 | developer
33 | debugger
34 | reviewer
35 | support
36 | maintainer
37 |
38 | +1
39 |
40 |
41 |
42 | scm:git:git://github.com/odinsbane/least-squares-in-java
43 | scm:git:git@github.com/odinsbane/least-squares-in-java
44 | HEAD
45 | https://github.com/odinsbane/least-squares-in-java
46 |
47 |
48 |
49 | junit
50 | junit
51 | 4.8.2
52 | test
53 |
54 |
55 | gov.nist.math
56 | jama
57 | 1.0.3
58 | compile
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | org.apache.maven.plugins
67 | maven-compiler-plugin
68 | 3.5.1
69 |
70 | 1.6
71 | 1.6
72 | true
73 | true
74 |
75 |
76 |
77 |
78 | org.apache.maven.plugins
79 | maven-source-plugin
80 | 3.0.0
81 |
82 |
83 | attach-sources
84 |
85 | jar
86 |
87 |
88 |
89 |
90 |
91 |
92 | org.apache.maven.plugins
93 | maven-javadoc-plugin
94 | 2.10.3
95 |
96 |
97 | attach-javadocs
98 |
99 | jar
100 |
101 |
102 | -Xdoclint:none
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/src/main/java/org/orangepalantir/filters/SavitzyGolayFilter.java:
--------------------------------------------------------------------------------
1 | package org.orangepalantir.filters;
2 | import Jama.LUDecomposition;
3 | import Jama.Matrix;
4 |
5 | /** Class implements the Savitzy-Golay filter. The algorithm is based on
6 | * the algorithm used in
7 | *
8 | * Numerical Methods in C: The art of scientific computing second edition
9 | *
10 | * This filter is used for smoothing data. The current implementation is
11 | * a 1-d approach and a symmetric 2-d approach.
12 | *
13 | *
14 | * @Author: Matthew B. Smith
15 | * @Url: http://orangepalantir.org
16 | * @Version: 0.8
17 | * @Date: 2/10/2010
18 | *
19 | **/
20 | public class SavitzyGolayFilter{
21 | double[] coefficients;
22 | int LEFT, RIGHT, ORDER;
23 | /**
24 | * Prepares the filter coefficients
25 | *
26 | * @param left number of places to the left of the origion
27 | * @param right number of places to the right of the origion
28 | * @param order of polynomial used to fit data
29 | * */
30 | public SavitzyGolayFilter(int left, int right, int order){
31 |
32 | coefficients = SavitzkyGolayCoefficients(left,right,order);
33 | LEFT = left;
34 | RIGHT = right;
35 | ORDER = order;
36 | }
37 |
38 | /**
39 | * Prepares the filter coefficients
40 | *
41 | * @param left number of places to the left of the origion
42 | * @param right number of places to the right of the origion
43 | * @param order of polynomial used to fit data
44 | * @param derivative use a SavitzkyGolayFilter to calculate the derivative or order.
45 | * */
46 | public SavitzyGolayFilter(int left, int right, int order, int derivative){
47 |
48 | coefficients = SavitzkyGolayCoefficients(left,right,order, derivative);
49 | LEFT = left;
50 | RIGHT = right;
51 | ORDER = order;
52 | }
53 |
54 |
55 | /**
56 | * filters the data by assuming the ends are reflected.
57 | *
58 | * @param data the array that is going to be filtered.
59 | * */
60 | public double[] filterData(double[] data){
61 | int pts = data.length;
62 | double[] ret_value = new double[pts];
63 |
64 | int j;
65 | //reflected
66 | for(j = 0; jorder - xp){
416 |
417 | yp = 0;
418 | xp++;
419 |
420 | }
421 | }
422 |
423 |
424 |
425 | Matrix rs = new Matrix(equals, M);
426 | Matrix ls = lud.solve(rs);
427 |
428 |
429 | //evaluate 2-d function;
430 | double sum = 0;
431 |
432 | xp = 0;
433 | yp = 0;
434 |
435 | for(int k = 0; korder - xp){
442 |
443 | yp = 0;
444 | xp++;
445 |
446 | }
447 | }
448 |
449 | kernel[j][i] = sum;
450 | }
451 |
452 | }
453 |
454 | return kernel;
455 | }
456 |
457 | /**
458 | * Evaluates a polynomial where:
459 | * p(x) = poly[0] * x**m + poly[1] * x**(m-1) + ... + poly[m]
460 | *
461 | * @param poly - double array representation of a polynomial
462 | * @param x - the variable that will be evaluated.
463 | **/
464 | public static double evaluatePolynomial(double[] poly, double x){
465 |
466 | double val = 0;
467 | int m = poly.length;
468 | for(int j = 0; j0){
79 | aafter[j-1] = A[j-1];
80 | abefore[j-1] = A[j-1];
81 | }
82 |
83 | for(int i = 0; iMath.abs(values[i][0])?max_change:Math.abs(values[i][0]);
128 | A[i] += values[i][0]*STEP;
129 | }
130 |
131 | return max_change;
132 |
133 |
134 | }
135 | public void iterateValuesB(){
136 | Matrix system = new Matrix(DERIVATIVES);
137 | Matrix params = new Matrix(ERROR,ERROR.length);
138 | //params = params.times(-1.);
139 | Matrix out = system.solve(params);
140 |
141 | double[][] values = out.getArray();
142 |
143 | for(int i = 0; ilast_error){
170 | System.err.println("Error increased: consider smaller step size.");
171 | break;
172 | }
173 | last_error = e;
174 | calculateDerivatives();
175 | try{
176 | changes = iterateValues();
177 | if(changes< MIN_CHANGE)
178 | break;
179 | } catch(Exception exc){
180 | throw new RuntimeException(exc);
181 | }
182 | }
183 | if(i==MAX_ITERATIONS){
184 | System.err.println("Warning: Maximum iteration reached.");
185 | }
186 |
187 |
188 | }
189 | /**
190 | * Gets the current set of parameters values.
191 | * */
192 | public double[] getParameters(){
193 | return A;
194 | }
195 |
196 | @Override
197 | public double[] getUncertainty() {
198 | return new double[0];
199 | }
200 |
201 | public void setStepSize(double step){
202 | STEP = step;
203 | }
204 |
205 | public void setMinError(double error){
206 | MIN_ERROR = error;
207 | }
208 |
209 | /**
210 | * When the parameters change less than the change parameter the program will stop iterating
211 | *
212 | * @param change
213 | */
214 | public void setMinChange(double change){
215 | MIN_CHANGE = change;
216 | }
217 |
218 | }
219 |
--------------------------------------------------------------------------------
/src/main/java/org/orangepalantir/leastsquares/functions/ExponentialFunction.java:
--------------------------------------------------------------------------------
1 | package org.orangepalantir.leastsquares.functions;
2 |
3 | import org.orangepalantir.leastsquares.Function;
4 |
5 | /**
6 | *
7 | * Created by msmith on 2/26/14.
8 | */
9 | public class ExponentialFunction implements Function {
10 | @Override
11 | public double evaluate(double[] values, double[] parameters) {
12 | return parameters[0] + parameters[1]*Math.exp(parameters[2]*values[0]);
13 | }
14 |
15 | @Override
16 | public int getNParameters() {
17 | return 3;
18 | }
19 |
20 | @Override
21 | public int getNInputs() {
22 | return 1;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/org/orangepalantir/leastsquares/functions/LinearFunction.java:
--------------------------------------------------------------------------------
1 | package org.orangepalantir.leastsquares.functions;
2 |
3 | import org.orangepalantir.leastsquares.Function;
4 |
5 | /**
6 | * Generic linear function, with an offset.
7 | *
8 | * A + B x1 + C x2 + D x3 ...
9 | *
10 | * Where the number of inputs, x's is indicated in the constructor and
11 | * the number of parameters is the number of terms plus 1.
12 | *
13 | * Created by msmith on 2/26/14.
14 | */
15 | public class LinearFunction implements Function {
16 | int terms;
17 | public LinearFunction(int terms){
18 | this.terms = terms;
19 | }
20 | @Override
21 | public double evaluate(double[] values, double[] parameters) {
22 | double sum = parameters[0];
23 | for(int i = 0; i