public static void test5() {
   MathFunc f = FX.x * FX.y * FX.z + 1;
   System.out.println(f);
   System.out.println(f.getVarNames());
   System.out.println(f.apply(2, 3, 4));
   CompiledFunc cf = f.compile();
   System.out.println(cf.apply(2, 3, 4));
 }
  public static void test2() {
    MathFunc x = FX.x;
    MathFunc y = FX.y;
    MathFunc xy = x.M(y);
    System.out.println(xy);
    HashMap<String, MathFunc> map = new HashMap<String, MathFunc>();
    map.put(x.getVarNames().get(0), FX.r.A(FX.s));
    map.put(y.getVarNames().get(0), FX.r.S(FX.s));
    MathFunc xy2 = xy.compose(map);
    System.out.println(xy2);

    System.out.println(FX.r.A(FX.s).M(FX.r.S(FX.s)));

    FuncClassLoader<CompiledFunc> fcl = new FuncClassLoader<CompiledFunc>();
    ClassGen genClass = BytecodeUtils.genClass(xy2, null, "add2", true, false);
    CompiledFunc fxy2 = fcl.newInstance(genClass);
    System.out.println(fxy2.apply(4.0, 2.0));
  }
  public static void test4() {
    FSin sin = new FSin("x");
    FCos cos = new FCos("y");
    MathFunc f = sin * cos;
    System.out.println(f);
    System.out.println(f.getVarNames());
    System.out.println(f.apply(Math.PI / 2, Math.PI / 4));

    CompiledFunc cf = f.compile();
    System.out.println(cf.apply(Math.PI / 2, Math.PI / 4));
    // bug in order of args
    System.out.println(f.compile(new String[] {"y", "x"}).apply(Math.PI / 2, Math.PI / 4));
  }
  /**
   * 构造下列形函数中的一个: N1 = L1 = r N2 = L2 = s N3 = L3 = t
   *
   * @param funID = 1,2,3
   */
  public void Create(int funID, double coef) {
    funIndex = funID - 1;
    if (funID < 1 || 3 < funID) {
      throw new FutureyeException("ERROR: funID should be 1,2 or 3.");
    }

    this.varNames = new String[] {"r", "s", "t"};
    innerVarNames = new ObjList<String>("x", "y");

    // Compose function: r = r(x,y), s = s(x,y), t = t(x,y)
    Map<String, MathFunc> fInners = new HashMap<String, MathFunc>();
    final String varName = varNames[funIndex];
    fInners.put(
        varName,
        new AbstractMathFunc(innerVarNames.toList()) {
          public MathFunc diff(String var) {
            if (area < 0.0) {
              throw new FutureyeException("Check nodes order: area < 0.0");
            } else {
              if (varName.equals("r")) { // r对应三角形高h的负倒数
                if (var.equals("x")) return new FC(b[0] / (2 * area));
                if (var.equals("y")) return new FC(c[0] / (2 * area));
              } else if (varName.equals("s")) { // s对应三角形高h的负倒数
                if (var.equals("x")) return new FC(b[1] / (2 * area));
                if (var.equals("y")) return new FC(c[1] / (2 * area));
              } else if (varName.equals("t")) { // t对应三角形高h的负倒数
                if (var.equals("x")) return new FC(b[2] / (2 * area));
                if (var.equals("y")) return new FC(c[2] / (2 * area));
              }
            }
            return null;
          }

          @Override
          public double apply(double... args) {
            throw new UnsupportedOperationException();
          }
        });

    // 使用复合函数构造形函数
    funOuter = new SF123();
    this.coef = coef;
    funCompose = FC.c(this.coef).M(funOuter.compose(fInners));
    funCompose.setActiveVarNames(funOuter.getVarNames());
  }