/**
   * procedure DynamicProgram
   *
   * <p>this function modifies bestRoots
   */
  public static void DynamicProgram() {

    /*
     * "java.lang.Object"のsubTypeを作成。
     */
    //		Type t_obj = types.get("java.lang.Object");
    //		for(Type t_sub: types.values())
    //			if(!t_sub.getName().equals("java.lang.Object"))
    //				t_obj.addSubType(t_sub.getName());

    // for each 1 <= i <= h
    for (int i = 0; i < HEIGHT; i++) {
      // for each t in T
      for (Type t : types.values()) {

        // bestRoots(t,i) = 0
        // for each f in F where ret(f) in sub(t)
        for (String subt : t.getSubTypes()) {

          for (Function f : functions) {

            if (f.getReturnType().equals(subt)) {
              //							if(i == 2 && t.getName().equals("java.lang.Object") &&
              // f.getParentClass().equals("java.util.List<java.lang.String>") &&
              // f.getName().equals("add")){
              //								System.out.println("jkjk");
              //							}
              // e = GetBestExplForFunc(f, i-1)
              FunctionTree tree = GetBestExplTreeForFunc(f, i);

              // if e > -∞ then bestRoots(t, i) = bestRoots(t, i)U(e, f)
              if (tree != null && tree.getEvaluationValue() > -9999.0) {
                bestRoots.addRoot(tree);
              }
            }
          }
        }
        // keep the best r roots
        bestRoots.keepBestRoots(t.getName(), i);
      }
    }
  }
  public static void printBestRoots() {
    for (int i = 0; i < HEIGHT; i++) {

      for (Type t : types.values()) {
        FunctionTree[] roots = bestRoots.getRoots(t.getName(), i);
        for (FunctionTree r : roots) {
          if (r != null) { // このnullチェックは必要
            System.out.print("i= " + i + ", ");
            System.out.print("ret_t_of_f= " + t.getName() + ", ");
            System.out.print("f= " + r.getRoot().getFunction().getName() + ", ");
            System.out.print("parent_t_of_f= " + r.getRoot().getFunction().getParentClass() + ", ");
            System.out.print("tree= " + r.toCompleteMethodString() + ", ");
            System.out.print("e= " + r.getEvaluationValue());
            System.out.println("");
          }
        }
        //				int count = bestRoots.getSizeOfRoots(t.getName(), i);
        //				if(roots.length > 0)
        //					System.out.println(i + ", "+ t.getName() + ", " + count);
      }
      System.out.println("");
    }
  }
  /**
   * procedure GetBestExplForFunc
   *
   * <p>最低でもRootのみのTreeは取得できる
   *
   * @param f
   * @param h_max
   * @return
   */
  public static FunctionTree GetBestExplTreeForFunc(Function f, int h_max) {

    //		if(f.getName().equals("getFruitList")){
    //			System.out.println("aaa");
    //		}

    /*
     * 親クラスが"this"かつ、非staticの場合は、レシーバ無しでも起動できるようにする。
     */
    boolean this_flg = false;
    if (f.getParentClass().equals("this") && f.isStatic() == false) {
      this_flg = true;
    }

    FunctionTree best_tree = new FunctionTree(f, input_keywords, numOfSameWords); // RootのみのTree
    ExplanationVector e_cumulative =
        new ExplanationVector(best_tree.e_vec); // best_treeのe_vecをコピーしてnew

    // for each p in params(f)

    if (f.getParameters() == null) return best_tree; // 関数に引数がないとき、rootのみを返す
    else if (h_max == 0) return null; // 関数に引数はあるが、高さが0のとき、nullを返す

    /*
     * this_flg=trueのときは、高さ0、引数レシーバのみのときがある。
     */
    if (this_flg == true && f.getParameters().length == 1) return best_tree;

    for (String param : f.getParameters()) { // 引数の順番通りにループする
      // e_best = (-∞, 0, 0, 0, ...)
      ExplanationVector e_best =
          new ExplanationVector(input_keywords.size(), -ExplanationVector.INFINITE_VALUE); // 空っぽ
      FunctionTree param_tree = null;
      // for each 1 <= i <= h
      for (int i = 0; i < h_max; i++) { // h_max=0の場合はこのループは実行されない
        // for each (e', f') in bestRoots(p, i)
        FunctionTree[] trees = bestRoots.getRoots(param, i);
        if (trees != null) {
          for (FunctionTree t : trees) {
            if (t != null) {
              // if e_cumulative + e' > e_best
              //    e_best = e_cumulative + e'

              ExplanationVector tmp = ExplanationVector.add(e_cumulative, t.e_vec);
              if (tmp.compareTo(e_best) == 1) {
                e_best.substitution(tmp); // 代入
                param_tree = t;
              }
            }
          }
        }
      }
      // e_cumulative = e_best
      e_cumulative.substitution(e_best);

      if (param_tree == null) return null; // 引数が1つでも埋まらなければ,そのroot関数は選択しない。nullを返す。
      else best_tree.addChild(param_tree);
    }

    return best_tree;
  }
  private static void printResult(
      String desiredType,
      ArrayList<Type> new_types,
      ArrayList<Function> new_funcs,
      long time,
      String state) {
    LogControl logControl = new LogControl(LogControl.KP);

    // コードコンプリーションのときはログ状態の表示を行う。サーチモードのときはログ状態の表示を毎回行わない。邪魔なので。
    if (state.equals(KpRunningState.CODE_COMPLETION)) logControl.printLogState();

    // new_typesに含まれる空文字列削除
    new_types.remove(new Type(""));

    logControl.println(">>> start keyword programming >>>");
    logControl.println("");

    logControl.println(" >> 基本情報 >>", LogControl.KP_BASIC);
    logControl.println(
        "  実行にかかった時間= " + time + " ミリ秒。KeywordProgramming.printResult", LogControl.KP_BASIC);
    logControl.println("  BEST_R =" + BEST_R);
    logControl.print("  入力キーワード= ", LogControl.KP_BASIC);
    for (String w : input_keywords) logControl.print(w + ", ", LogControl.KP_BASIC);
    logControl.println("");
    logControl.println("  出力候補の望ましい返り値の型= " + desiredType, LogControl.KP_BASIC);
    logControl.println("  入力キーワード数=" + input_keywords.size());
    logControl.println("  総型数= " + types.size(), LogControl.KP_BASIC);
    if (new_types != null)
      logControl.println("  ローカルの型数= " + new_types.size(), LogControl.KP_BASIC);
    logControl.println("  総関数数= " + functions.size(), LogControl.KP_BASIC);
    if (new_funcs != null)
      logControl.println("  ローカルの関数数= " + new_funcs.size(), LogControl.KP_BASIC);
    if (outputFunctionTrees != null)
      logControl.println("  生成された出力の総数= " + outputFunctionTrees.length, LogControl.KP_BASIC);

    logControl.println(
        "  特徴の重みの組= (" + ExplanationVector.getWeightString() + ")", LogControl.KP_BASIC);

    logControl.println(" << 基本情報 <<", LogControl.KP_BASIC);
    logControl.println("", LogControl.KP_BASIC);

    if (new_types != null)
      logControl.println("  ローカルの型数= " + new_types.size(), LogControl.KP_TYPES);
    logControl.println(" >> ローカルの型一覧 >>", LogControl.KP_TYPES);
    if (new_types != null) {
      for (Type t : new_types) {
        logControl.println("  " + t.toDBString(), LogControl.KP_TYPES);
      }
    }
    logControl.println(" << ローカルの型一覧 <<", LogControl.KP_TYPES);
    logControl.println("", LogControl.KP_TYPES);

    if (new_funcs != null)
      logControl.println("  ローカルの関数数= " + new_funcs.size(), LogControl.KP_FUNCTIONS);
    logControl.println(
        " >> ローカルの関数一覧 >> 出力形式:[親クラス名, isStatic, isFinal, type(field or constructor or method or localvariable), 返り値の型, 名前, ラベル(区切り文字;), 引数の型(何個でも) ]",
        LogControl.KP_FUNCTIONS);
    if (new_funcs != null) {
      for (Function f : new_funcs) {
        logControl.println("  " + f.toDBString(), LogControl.KP_FUNCTIONS);
      }
    }
    logControl.println(
        " << ローカルの関数一覧s << 出力形式:[親クラス名, isStatic, isFinal, type(field or constructor or method or localvariable), 返り値の型, 名前, ラベル(区切り文字;), 引数の型(何個でも) ]",
        LogControl.KP_FUNCTIONS);
    logControl.println("", LogControl.KP_FUNCTIONS);

    logControl.println(
        " >> 出力候補一覧 >> 出力形式:[評価値, p(4つの特徴量), e_i(長さはキーワード数に等しい), 出力文字列]", LogControl.KP_RESULTS);
    for (FunctionTree t : outputFunctionTrees) {
      if (t != null) {
        logControl.println(
            "  " + t.toEvalString() + t.toCompleteMethodString(), LogControl.KP_RESULTS);
        //					logControl.out(t.toLogDBString());
      }
    }
    logControl.println(
        " << 出力候補一覧 << 出力形式:[評価値, p(4つの特徴量), e_i(長さはキーワード数に等しい), 出力文字列]", LogControl.KP_RESULTS);
    logControl.println("", LogControl.KP_RESULTS);

    logControl.println("<<< end keyword programming <<<");
    logControl.close();
  }