2

I made a test program to try the NewtonRaphsonSolver class through the Apache Commons Math library. Newton's method is used to find roots for a given function.

The test program that I wrote references the cos(x) function (I have a more difficult function to analyze and am looking at the cos(x) function first).

The code for the test program is

import org.apache.commons.math3.analysis.differentiation.DerivativeStructure;
import org.apache.commons.math3.analysis.differentiation.UnivariateDifferentiableFunction;
import org.apache.commons.math3.analysis.solvers.*;
import org.apache.commons.math3.exception.DimensionMismatchException;

public class Test3 {

    public static void main(String args[]) {
        NewtonRaphsonSolver test = new NewtonRaphsonSolver();
        UnivariateDifferentiableFunction f = new UnivariateDifferentiableFunction() {

            public double value(double x) {
                return Math.cos(x);
            }

            @Override
            public DerivativeStructure value(DerivativeStructure t) throws DimensionMismatchException {
                return t.cos();
            }
        };

        for (int i = 1; i <= 500; i++) {
            System.out.println(test.solve(1000, f, i, i+0.1));
        }
    }
}

Not certain if I needed to reference Math.cos(x) and t.cos() twice

public double value(double x) {
                return Math.cos(x);
            }

            @Override
            public DerivativeStructure value(DerivativeStructure t) throws DimensionMismatchException {
                return t.cos();
            }

Newton's method finds all of the zeroes and displays them to the user.

1.5707963267948966
1.5707963267948966
-7.853981633974483
4.71238898038469
4.71238898038469
1.5707963267948966
7.853981633974483
7.853981633974483
10.995574287564276
10.995574287564276
10.995574287564276
10.995574287564276
14.137166941154069
14.137166941154069
14.137166941154069
127.23450247038663
17.278759594743864
17.278759594743864
23.56194490192345
20.420352248333657
20.420352248333657
39.269908169872416
23.56194490192345
23.56194490192345
14.137166941154069
26.703537555513243
26.703537555513243
23.56194490192345
29.845130209103036
29.845130209103036
26.703537555513243
32.98672286269283
32.98672286269283
32.98672286269283
36.12831551628262
36.12831551628262
36.12831551628262
23.56194490192345
39.269908169872416
39.269908169872416
45.553093477052
42.411500823462205
42.411500823462205

Is there some way to prevent printing out zeroes that are duplicates? For example, the above output would read

1.5707963267948966
4.71238898038469
7.853981633974483
10.995574287564276
14.137166941154069
17.278759594743864
20.420352248333657
23.56194490192345
26.703537555513243
29.845130209103036
32.98672286269283
36.12831551628262
39.269908169872416
42.411500823462205
45.553093477052

Can this be done inside a for loop or through an array which only prints out values which are not duplicates?

Matt Taylor
  • 3,360
  • 1
  • 20
  • 34
Axion004
  • 943
  • 1
  • 11
  • 37

2 Answers2

2

First question is , what are the same zeros. I would make a class:

class SolutionForZero{
    public final double value;
    final int hash;
    static double tolerance = 1e-6;
    public SolutionForZero(double value){
        this.value = value;
        hash = 1;
    }
    public boolean equals(Object other){
        if( other instanceof SolutionForZero ){
           double v = value - other.value;
           return (v < 0) ? (-v > tolerance) : (v > tolerance);
        }
        return false;
    }
    public int hashCode(){
        return hash;
    }
}

This class will compare the doubles. To use this class:

Set<SolutionForZero> resultSet = new HashSet<>();
for(double d: yourAnswers){
    if(resultSet.add(new SolutionForZero(d))){
        System.out.println("'unique' zero at: " + d);
    };
}

Now your resultSet will contain only values that are at least tolerance apart.

The hashcode is a bit tricky. The way I have provided will work as long as tolerance is smaller than 1.0. I would appreciate improvements.

matt
  • 10,892
  • 3
  • 22
  • 34
  • The public final double value and final int hash don't compile because they have not been initialized. – Axion004 Sep 10 '15 at 12:08
  • return v<0?-v>tolerance:v>tolerance; Man, whitespaces are generally cheap, at first glance it looked like returning some kind of generics – piezol Sep 10 '15 at 12:57
  • 1
    @Axion004 They're set in the constructor. – matt Sep 10 '15 at 13:07
  • @piezol The hashcode should match for classes that are equal. If I want to define equal as being within a small tolerance then equal doubles would have different hashcodes. – matt Sep 10 '15 at 13:09
  • 1
    @Axion, I named the constructor wrong. Sorry about that. – matt Sep 10 '15 at 13:14
  • I found an alternative solution. – Axion004 Sep 11 '15 at 22:29
  • 1
    Your class `SolutionForZero` *does not respect* the `hashCode`/`equals` contract: in your class two values with different hash can be equals. Bundling together similar values up to a tolerance is a bit more complex than that, you should use a clustering algorithm. – Laurent Grégoire Oct 28 '15 at 08:56
  • @Laurent do you have an example of the violation? – matt Oct 28 '15 at 09:34
  • 1
    @matt 1.999999999 and 2.000000001. The first one will hash to 0 and the second to 1, but both values are "equals". – Laurent Grégoire Oct 28 '15 at 09:52
  • Hmm, it is a small step to say, given 3 values, a,b,c where |a-b| – matt Oct 28 '15 at 10:16
1
import java.util.TreeSet;
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure;
import org.apache.commons.math3.analysis.differentiation.UnivariateDifferentiableFunction;
import org.apache.commons.math3.analysis.solvers.*;
import org.apache.commons.math3.exception.DimensionMismatchException;

public class Test5 {

    public static void main(String args[]) {
        NewtonRaphsonSolver test = new NewtonRaphsonSolver(1E-10);

        UnivariateDifferentiableFunction f = new UnivariateDifferentiableFunction() {

            public double value(double x) {
                return Math.sin(x);
            }

            public DerivativeStructure value(DerivativeStructure t) throws
                    DimensionMismatchException {
                return t.sin();
            }
        };

        double EPSILON = 1e-6;
        TreeSet<Double> set = new TreeSet<>();
        for (int i = 1; i <= 5000; i++) {
            set.add(test.solve(1000, f, i, i + EPSILON));
        }
        for (Double s : set) {
            if (s > 0) {
                System.out.println(s);
            }
        }
    }
}
Axion004
  • 943
  • 1
  • 11
  • 37