0

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.

aknight0
  • 163
  • 2
  • 14
  • Do you have these 'variety of piecewise' functions available in a Java class? – sperumal Jun 26 '12 at 21:48
  • If you are looking for MathML interpreter, it doesn't exist. Please see http://stackoverflow.com/questions/2973248/is-there-a-library-to-evaluate-mathml-expressions. – sperumal Jun 26 '12 at 21:55
  • If this doesn't have to be in Java, check out R. Write the function, feed it with a bunch of values and graph the result. – Jochen Jun 26 '12 at 23:46
  • Maybe Google's [guava](http://code.google.com/p/guava-libraries/wiki/FunctionalExplained) with `Function` is what you are looking for. – Joop Eggen Jun 27 '12 at 01:34

1 Answers1

1

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.

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • This is definitely a start, however my main problem is creating a more general converter so that I don't have to write a special case for each possible piecewise expression. – aknight0 Jun 27 '12 at 18:46
  • I have encoded your examples (as A, B, C, D, E and F) and used a general algorithm to generate a csv for each. I think all that is left is some rounding rules and you're done, unless I have misunderstood your question. – OldCurmudgeon Jun 27 '12 at 21:19
  • Ah, I had misunderstood what you were doing. – aknight0 Jun 28 '12 at 17:07