Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run java classes larger than 64k in an effort to solve a non linear system of equations [duplicate]

Tags:

java

I am trying to solve a system of nonlinear functions in java. Particularly I have 3 equations with 3 unknown variables. Although I have managed to solve simple equations, my final goal is to solve some pretty big ones. For example, each equation consists of hundreds of lines (sometimes even thousands) in the form of:

 public static double f2 (double x, double y, double z) {
        double result = (0.49*Math.exp(-y - x)*Math.pow(x,2)*
                (1 - Math.pow(z,94)*(0.00666 +
                        0.98*Math.exp(-y - x) + 0.98*Math.exp(-y - x)*
                        y*x + 0.245*Math.exp(-y - x)*Math.pow(y,2)*
                        Math.pow(x,2) + 0.02722*
                        Math.exp(-y - x)*Math.pow(y,3)*Math.pow(x,3) +
                        0.00170*Math.exp(-y - x)*
                                Math.pow(y,4)*Math.pow(x,4) + 0.00006*
                        Math.exp(-y - x)*Math.pow(y,5)*Math.pow(x,5) +
                        1.89043*Math.pow(10,-6)*Math.exp(-y - x)*
                                Math.pow(y,6)*Math.pow(x,6) + 3.85802*Math.pow(10,-8)*
                        Math.exp(-y - x)*Math.pow(y,7)*Math.pow(x,7) +
                        6.02816*Math.pow(10,-10)*Math.exp(-y - x)*
                                Math.pow(y,8)*Math.pow(x,8) + 7.44217*Math.pow(10,-12)*
                        Math.exp(-y - x)*Math.pow(y,9)*Math.pow(x,9) +
                        7.44217*Math.pow(10,-14)*Math.exp(-y - x)*
                                Math.pow(y,10)*Math.pow(x,10))))/(0.01333 +
                0.98*Math.exp(-y - x)*y +
                0.49*Math.exp(-y - x)*Math.pow(y,2) +
                0.16333*Math.exp(-y - x)*Math.pow(y,3) +
                0.04083*Math.exp(-y - x)*Math.pow(y,4) +
                0.00816*Math.exp(-y - x)*Math.pow(y,5) + .....

The problem is that two of my classes are significantly larger than 65k, particularly 650k/ class so I am out of limitations.

Is there any way to run/ compile my code, overcoming this limits?

My 3 equations have been generated from another language (wolfram) but I need to implement my goal in java (mathematical/matlab etc is not n option).

This answer suggests using .properties but I cannot see how this can help in my case ("Code too large" compilation error in Java)

like image 587
Fierce82 Avatar asked Oct 30 '17 11:10

Fierce82


2 Answers

The limit of 64K is applicable to a method, so you can put your code into different methods that are called one after the other passing the intermediate result.

If you reach a class-size limit (I'm not aware of one but the last time I ran into this problem myself was in the year 2000 and with Java 1.1), you can do the same trick and separate your code over multiple classes. Inner classes should be OK for this, so you still can output your code into one source file.

Edit: You can also look for calculation results that can be reused. For example you calculate Math.exp(-y - x) quite often. Putting that into a temporary variable should save space and should make the whole calculation significantly faster. As well there's the same kind of calculation taking place that can be put into its own method:

0.98*Math.exp(-y - x)*y +
0.49*Math.exp(-y - x)*Math.pow(y,2) +
0.16333*Math.exp(-y - x)*Math.pow(y,3) +
0.04083*Math.exp(-y - x)*Math.pow(y,4) +
0.00816*Math.exp(-y - x)*Math.pow(y,5) + ...

could be change to the following (typed directly into this text, so there might be compile errors IRL):

private static double calcLoop(double x, double y, int max) {
    double expVal = Math.exp(-y - x);
    double startVal = 0.98;
    double sum = startVal * y
    for (int i = 2; i <= max; i++) {
        startVal = startVal / i;
        sum += startVal * Math.pow(y, i);
    }
    return sum * expVal;
}

This method also "optimized" the calculation by only multiplying the resulting sum with expVal

like image 122
Lothar Avatar answered Sep 27 '22 18:09

Lothar


The problem here is a 64k limit on the bytecode of a method, so the only option is to split things up. The minimal approach to this is to identify large, extractable sequences and pull them out. Take, for example:

                    0.98*Math.exp(-y - x) + 0.98*Math.exp(-y - x)*
                    y*x + 0.245*Math.exp(-y - x)*Math.pow(y,2)*
                    Math.pow(x,2) + 0.02722*
                    Math.exp(-y - x)*Math.pow(y,3)*Math.pow(x,3) +
                    0.00170*Math.exp(-y - x)*
                            Math.pow(y,4)*Math.pow(x,4) + 0.00006*
                    Math.exp(-y - x)*Math.pow(y,5)*Math.pow(x,5) +
                    1.89043*Math.pow(10,-6)*Math.exp(-y - x)*
                            Math.pow(y,6)*Math.pow(x,6) + 3.85802*Math.pow(10,-8)*
                    Math.exp(-y - x)*Math.pow(y,7)*Math.pow(x,7) +
                    6.02816*Math.pow(10,-10)*Math.exp(-y - x)*
                            Math.pow(y,8)*Math.pow(x,8) + 7.44217*Math.pow(10,-12)*

As none of these lines have non-matched braces and we know it is all one equation (no variables change in the course of calculation), they can be safely extracted as a block with identical function parameters:

 public static double a1 (double x, double y, double z) {
    return 0.98*Math.exp(-y - x) + 0.98*Math.exp(-y - x)*
                    y*x + 0.245*Math.exp(-y - x)*Math.pow(y,2)*
                    Math.pow(x,2) + 0.02722*
                    Math.exp(-y - x)*Math.pow(y,3)*Math.pow(x,3) +
                    0.00170*Math.exp(-y - x)*
                            Math.pow(y,4)*Math.pow(x,4) + 0.00006*
                    Math.exp(-y - x)*Math.pow(y,5)*Math.pow(x,5) +
                    1.89043*Math.pow(10,-6)*Math.exp(-y - x)*
                            Math.pow(y,6)*Math.pow(x,6) + 3.85802*Math.pow(10,-8)*
                    Math.exp(-y - x)*Math.pow(y,7)*Math.pow(x,7) +
                    6.02816*Math.pow(10,-10)*Math.exp(-y - x)*
                            Math.pow(y,8)*Math.pow(x,8) + 7.44217*Math.pow(10,-12);
}

This can then be injected into the original function as so:

public static double f2 (double x, double y, double z) {
    double result = (0.49*Math.exp(-y - x)*Math.pow(x,2)*
            (1 - Math.pow(z,94)*(0.00666 +
                    a1()*
                    Math.exp(-y - x)*Math.pow(y,9)*Math.pow(x,9) +
                    7.44217*Math.pow(10,-14)*Math.exp(-y - x)*
                            Math.pow(y,10)*Math.pow(x,10))))/(0.01333 +
            0.98*Math.exp(-y - x)*y +
            0.49*Math.exp(-y - x)*Math.pow(y,2) +
            0.16333*Math.exp(-y - x)*Math.pow(y,3) +
            0.04083*Math.exp(-y - x)*Math.pow(y,4) +
            0.00816*Math.exp(-y - x)*Math.pow(y,5) + .....

This clearly makes no effort to optimise or eliminate duplication; it's the simplest technique to overcome the method size limit.

like image 43
Danikov Avatar answered Sep 27 '22 17:09

Danikov