Search code examples
javacsvmathmlpiecewise

Convert a piecewise function to a CSV file using Java


I'm trying to create a Java function that will convert a string containing a piecewise function to a CSV file that can be used for graphing. For example this expression:

if (time < 60) then (0.1) else ( if (time > 66.0115) then (0.1) else 1)

would be converted to:

File pwl.csv
time , output
0 , 0.1 
59.9, 0.1
60, 1
66.0115, 1
66.11149999999999, 0.1
132.023, 0.1
End File

The converter needs to be able to handle a variety of piecewise functions, including:

if (t > 0.5) then (2) else 3
if (t >= 0.5) then (2) else 3
if (t < 0.5) then (2) else 3
if (t <= 0.5) then (2) else 3
if ((t >= 3600) & (t <= 3660)) then (25) else 0

I've been able to write code that converted the first example, but it really only works for that specific function, and I'm looking for a more general solution. Any thoughts on the problem?

These piecewise functions originally came from a MathML file, so any suggestions for a direct conversion from MathML to CSV are welcome as well.


Solution

  • This seems to work - sort of. It would probably be a good start anyway.

    public class CSVFun {
      // Where to start the scan of the function.
      static final double Start = 0.0;
      // End of scan.
      static final double End = 10000.0;
      // Fine enough to detect a change in the function.
      static final double BigStep = 0.1;
      // Finest resolution.
      static final double SmallStep = 0.000000001;
    
      // Work out some csv for a function.
      private static void csv(F f) {
        System.out.println("Function: " + f);
        // Start at 0.
        double t = Start;
        double ft = f.f(t);
        System.out.println(t + "," + ft);
        while (t < End) {
          // Walk to the end.
          double step = BigStep;
          // Find a break point.
          while (t < End && f.f(t) == ft) {
            t += step;
          }
          if (t < End) {
            // Back one.
            t -= step;
            // Zoom in on the transition point.
            while (step > SmallStep) {
              // Go smaller.
              step /= 10;
              // Walk forward.
              while (t < End && f.f(t) == ft) {
                t += step;
              }
              // Back one.
              t -= step;
            }
            // Before
            System.out.println(t + "," + ft);
            // One more forward.
            t += step;
          }
          // Print.
          if (f.f(t) != ft) {
            ft = f.f(t);
            System.out.println(t + "," + ft);
          }
        }
      }
    
      // Tests the process with the sample functions below.
      public static void main(String[] args) {
        try {
          for (F f : F.values()) {
            csv(f);
          }
        } catch (Exception ex) {
          ex.printStackTrace();
        }
      }
    
      // The sample functions - Encoded in Java
      enum F {
        A {
          @Override
          double f(double t) {
            if (t < 60) {
              return (0.1);
            }
            if (t > 66.0115) {
              return (0.1);
            }
            return 1;
          }
        },
        B {
          @Override
          double f(double t) {
            if (t > 0.5) {
              return 2;
            }
            return 3;
          }
        },
        C {
          @Override
          double f(double t) {
            if (t >= 0.5) {
              return 2;
            }
            return 3;
          }
        },
        D {
          @Override
          double f(double t) {
            if (t < 0.5) {
              return 2;
            }
            return 3;
          }
        },
        E {
          @Override
          double f(double t) {
            if (t <= 0.5) {
              return 2;
            }
            return 3;
          }
        },
        F {
          @Override
          double f(double t) {
            if ((t >= 3600) & (t <= 3660)) {
              return 25;
            }
            return 0;
          }
        },;
    
        abstract double f(double t);
      }
    }
    

    Output:

    Function: A
    0.0,0.1
    59.999999999000565,0.1
    60.00000000000056,1.0
    66.01149999900045,1.0
    66.01150000000045,0.1
    Function: B
    0.0,3.0
    0.49999999999999994,3.0
    0.500000001,2.0
    Function: C
    0.0,3.0
    0.49999999999999983,3.0
    0.5000000009999999,2.0
    Function: D
    0.0,2.0
    0.49999999999999983,2.0
    0.5000000009999999,3.0
    Function: E
    0.0,2.0
    0.49999999999999994,2.0
    0.500000001,3.0
    Function: F
    0.0,0.0
    3599.9999999998213,0.0
    3600.0000000008213,25.0
    3659.999999999771,25.0
    3660.000000000771,0.0
    

    Which is close I think.