processing

How to import a library/package into a Processing sketch


I'm learning the Processing 4 programming app along with Java, which it uses. I have created a sketch and now want to add a library I downloaded, name Jama, to solve a system of linear equations. According to the Processing help, I need to create a directory named libraries in the sketch folder and put the library there, which I did. However, when I try and import it (import Jama.*), the app complains that it can't find it. As downloaded, the Jama package includes .java and .class files for each class. Is there something more I need to do to make this library available?


Solution

  • For the Contribution Manager (Add Library..." from the "Import Library..." submen) to work with the Jama library, it needs to be wrapped as a Processing library ideally.

    If you simply want to use the library in a test sketch you can do so without wrapping Jama as a Processing library:

    1. Download the Jama library .jar file
    2. Make a new Processing Sketch and save it
    3. Drag and drop the Jama-1.0.3.jar on top of your sketch. (This will create a subfolder named "code" in your sketch)

    You should be able to test importing the library and running the sketch (e.g. import Jama.*;).

    Here is the Jama example as a Processing sketch:

    import Jama.*; 
    import java.util.Date;
    
     /* 
    | Tests LU, QR, SVD and symmetric Eig decompositions.
    |
    |   n       = order of magic square.
    |   trace   = diagonal sum, should be the magic sum, (n^3 + n)/2.
    |   max_eig = maximum eigenvalue of (A + A')/2, should equal trace.
    |   rank    = linear algebraic rank,
    |             should equal n if n is odd, be less than n if n is even.
    |   cond    = L_2 condition number, ratio of singular values.
    |   lu_res  = test of LU factorization, norm1(L*U-A(p,:))/(n*eps).
    |   qr_res  = test of QR factorization, norm1(Q*R-A)/(n*eps).
    */
    void setup(){
      print("\n    Test of Matrix Class, using magic squares.\n");
      println("Test");
      print("    See MagicSquareExample.main() for an explanation.\n");
      print("\n      n     trace       max_eig   rank        cond      lu_res      qr_res\n\n");
       
      Date start_time = new Date();
      double eps = Math.pow(2.0,-52.0);
      for (int n = 3; n <= 32; n++) {
         print(fixedWidthIntegertoString(n,7));
      
         Matrix M = magic(n);
      
         int t = (int) M.trace();
         print(fixedWidthIntegertoString(t,10));
      
         EigenvalueDecomposition E =
            new EigenvalueDecomposition(M.plus(M.transpose()).times(0.5));
         double[] d = E.getRealEigenvalues();
         print(fixedWidthDoubletoString(d[n-1],14,3));
      
         int r = M.rank();
         print(fixedWidthIntegertoString(r,7));
      
         double c = M.cond();
         print(c < 1/eps ? fixedWidthDoubletoString(c,12,3) :
            "         Inf");
      
         LUDecomposition LU = new LUDecomposition(M);
         Matrix L = LU.getL();
         Matrix U = LU.getU();
         int[] p = LU.getPivot();
         Matrix R = L.times(U).minus(M.getMatrix(p,0,n-1));
         double res = R.norm1()/(n*eps);
         print(fixedWidthDoubletoString(res,12,3));
      
         QRDecomposition QR = new QRDecomposition(M);
         Matrix Q = QR.getQ();
         R = QR.getR();
         R = Q.times(R).minus(M);
         res = R.norm1()/(n*eps);
         print(fixedWidthDoubletoString(res,12,3));
      
         print("\n");
      }
      Date stop_time = new Date();
      double etime = (stop_time.getTime() - start_time.getTime())/1000.;
      print("\nElapsed Time = " + 
         fixedWidthDoubletoString(etime,12,3) + " seconds\n");
      print("Adios\n");
    }
    
    Matrix magic (int n) {
    
        double[][] M = new double[n][n];
    
        // Odd order
    
        if ((n % 2) == 1) {
           int a = (n+1)/2;
           int b = (n+1);
           for (int j = 0; j < n; j++) {
              for (int i = 0; i < n; i++) {
                 M[i][j] = n*((i+j+a) % n) + ((i+2*j+b) % n) + 1;
              }
           }
    
        // Doubly Even Order
    
        } else if ((n % 4) == 0) {
           for (int j = 0; j < n; j++) {
              for (int i = 0; i < n; i++) {
                 if (((i+1)/2)%2 == ((j+1)/2)%2) {
                    M[i][j] = n*n-n*i-j;
                 } else {
                    M[i][j] = n*i+j+1;
                 }
              }
           }
    
        // Singly Even Order
    
        } else {
           int p = n/2;
           int k = (n-2)/4;
           Matrix A = magic(p);
           for (int j = 0; j < p; j++) {
              for (int i = 0; i < p; i++) {
                 double aij = A.get(i,j);
                 M[i][j] = aij;
                 M[i][j+p] = aij + 2*p*p;
                 M[i+p][j] = aij + 3*p*p;
                 M[i+p][j+p] = aij + p*p;
              }
           }
           for (int i = 0; i < p; i++) {
              for (int j = 0; j < k; j++) {
                 double t = M[i][j]; M[i][j] = M[i+p][j]; M[i+p][j] = t;
              }
              for (int j = n-k+1; j < n; j++) {
                 double t = M[i][j]; M[i][j] = M[i+p][j]; M[i+p][j] = t;
              }
           }
           double t = M[k][0]; M[k][0] = M[k+p][0]; M[k+p][0] = t;
           t = M[k][k]; M[k][k] = M[k+p][k]; M[k+p][k] = t;
        }
        return new Matrix(M);
     }
    
    String fixedWidthDoubletoString (double x, int w, int d) {
        java.text.DecimalFormat fmt = new java.text.DecimalFormat();
        fmt.setMaximumFractionDigits(d);
        fmt.setMinimumFractionDigits(d);
        fmt.setGroupingUsed(false);
        String s = fmt.format(x);
        while (s.length() < w) {
           s = " " + s;
        }
        return s;
    }
    
    String fixedWidthIntegertoString (int n, int w) {
        String s = Integer.toString(n);
        while (s.length() < w) {
           s = " " + s;
        }
        return s;
    }
    

    Output:

        Test of Matrix Class, using magic squares.
    Test
        See MagicSquareExample.main() for an explanation.
    
          n     trace       max_eig   rank        cond      lu_res      qr_res
    
          3        15        15.000      3       4.330       0.000      11.333
          4        34        34.000      3         Inf       0.000      13.500
          5        65        65.000      5       5.462       0.000      14.400
          6       111       111.000      5         Inf       5.333      16.000
          7       175       175.000      7       7.111       2.286      37.714
          8       260       260.000      3         Inf       0.000      59.000
          9       369       369.000      9       9.102       7.111      53.333
         10       505       505.000      7         Inf       3.200     159.200
         11       671       671.000     11      11.102       2.909     215.273
         12       870       870.000      3         Inf       0.000     185.333
         13      1105      1105.000     13      13.060       4.923     313.846
         14      1379      1379.000      9         Inf       4.571     540.571
         15      1695      1695.000     15      15.062       4.267     242.133
         16      2056      2056.000      3         Inf       0.000     488.500
         17      2465      2465.000     17      17.042       7.529     267.294
         18      2925      2925.000     11         Inf       7.111     520.889
         19      3439      3439.000     19      19.048      16.842     387.368
         20      4010      4010.000      3         Inf      14.400     584.800
         21      4641      4641.000     21      21.035       6.095    1158.095
         22      5335      5335.000     13         Inf       6.545    1132.364
         23      6095      6095.000     23      23.037      11.130    1268.870
         24      6924      6924.000      3         Inf      10.667     827.500
         25      7825      7825.000     25      25.029      35.840    1190.400
         26      8801      8801.000     15         Inf       4.923    1859.077
         27      9855      9855.000     27      27.032      37.926    1365.333
         28     10990     10990.000      3         Inf      34.286    1365.714
         29     12209     12209.000     29      29.025      30.897    1647.448
         30     13515     13515.000     17         Inf       8.533    2571.733
         31     14911     14911.000     31      31.027      33.032    1426.581
         32     16400     16400.000      3         Inf       0.000    1600.125
    
    Elapsed Time =        0.046 seconds
    Adios
    

    If you don't want to keep copying the Jama-1.0.3.jar file into every new sketch, you can try this:

    1. Rename Jama-1.0.3.jar to Jama.jar
    2. Mimic the Processing library folder structure with nested folders: e.g. Documents/Processing/libraries/Jama/library
    3. Copy Jama.jar to Documents/Processing/libraries/Jama/library

    Once you restart Processing you should be able to import Jama.*; from any new sketch.

    Note that if you switch computers/want to work collaborately you need to share the Jama/library so it can be placed in Documents/Processing/libraries. With a tiny bit of extra effort it won't be complicated to wrap as a Processing library and share with community (so your future self and others can find it in the Contribution Manager). This is also an opportunity to add wrapper functions to simplify syntax as needed (e.g. override methods to work with floats where needed, utilities to plot/draw results, etc.)