示例#1
0
  /** It applies the migration stage */
  void Migration() {
    int i, j, num;
    double u;

    /* First, the individual in the population are ordered according to their fitness */
    Collections.sort(Poblacion);

    /* The second half (the worst one) is radomly initialized again */
    for (j = (tamPoblacion / 2); j < tamPoblacion; j++) {
      /* First, the antecedent */
      for (i = 0; i < entradas; i++) {
        Poblacion.get(j).antecedente[i].m =
            Randomize.RanddoubleClosed(train.getMin(i), train.getMax(i));
        Poblacion.get(j).antecedente[i].sigma = Randomize.RandintClosed(1, 4);
      }

      /* Secondly, the consequent */
      do {
        num = 0;

        for (i = 0; i < entradas; i++) {
          u = Randomize.RandClosed();
          /* The term is used in the consequent */
          if (u < 0.5) {
            Poblacion.get(j).consecuente[i] = Randomize.RanddoubleClosed(-1.0, 1.0);
            //                    Poblacion.get(j).consecuente[entradas] =
            // Randomize.RanddoubleClosed(-45.0, 45.0);
            if (Poblacion.get(j).consecuente[i] != 0.0) {
              num++;
            }
          }
          /* The term is NOT used in the consequent */
          else {
            Poblacion.get(j).consecuente[i] = 0.0;
          }
        }

        u = Randomize.RandClosed();
        /* The term is used in the consequent */
        if (u < 0.5) {
          Poblacion.get(j).consecuente[entradas] =
              Randomize.RanddoubleClosed(
                  -1.0 * ((train.getMax(entradas) - train.getMin(entradas)) / 2.0),
                  ((train.getMax(entradas) - train.getMin(entradas)) / 2.0));
          //                    Poblacion.get(j).consecuente[entradas] =
          // Randomize.RanddoubleClosed(-45.0, 45.0);
          //                Poblacion.get(j).consecuente[entradas] =
          // Randomize.RanddoubleClosed(train.getMin(entradas), train.getMax(entradas));
          if (Poblacion.get(j).consecuente[entradas] != 0.0) {
            num++;
          }
        }
        /* The term is NOT used in the consequent */
        else {
          Poblacion.get(j).consecuente[entradas] = 0.0;
        }
      } while (num == 0);
    }
  }
示例#2
0
  /**
   * It accumulates de fitness value (obtained by the evaluation function) among all the rules
   * forming the fuzzy system
   *
   * @param valor double The fitness value obtained by the evaluation function
   */
  void Accumulate_fitness_fuzzy_system(double valor) {
    int i;

    for (i = 0; i < Nr; i++) {
      Poblacion.get(vectorNr[i]).fitness += (valor / Nr);
    }
  }
示例#3
0
  /**
   * It selects one parent to participate in the evolutionary process (by binary tournament
   * selection).
   *
   * @param int The position in the population for the selected parent
   */
  int Selection() {
    int result;
    int[] indiv = new int[2];

    indiv[0] = Randomize.RandintClosed(0, ((tamPoblacion / 2) - 2));
    do {
      indiv[1] = Randomize.RandintClosed(0, ((tamPoblacion / 2) - 2));
    } while (indiv[0] == indiv[1]);

    if (Poblacion2.get(indiv[0]).fitness > Poblacion2.get(indiv[1]).fitness) {
      result = indiv[0];
    } else {
      result = indiv[1];
    }

    return (result);
  }
示例#4
0
  /** It initializes each individual in the population */
  void initializePopulation() {
    int i, j, num;
    double u;

    for (j = 0; j < tamPoblacion; j++) {
      /* First, the antecedent */
      for (i = 0; i < entradas; i++) {
        Poblacion.get(j).antecedente[i].m =
            Randomize.RanddoubleClosed(train.getMin(i), train.getMax(i));
        Poblacion.get(j).antecedente[i].sigma = Randomize.RandintClosed(1, 4);
      }

      /* Secondly, the consequent */
      do {
        num = 0;

        for (i = 0; i < entradas; i++) {
          u = Randomize.RandClosed();
          /* The term is used in the consequent */
          if (u < 0.5) {
            Poblacion.get(j).consecuente[i] = Randomize.RanddoubleClosed(-1.0, 1.0);
            //                        Poblacion.get(j).consecuente[i] =
            // Randomize.RanddoubleClosed(train.getMin(i) - 45.0, train.getMax(i) + 45.0);
            //                        Poblacion.get(j).consecuente[i] =
            // Randomize.RanddoubleClosed(-45.0, 45.0);
            if (Poblacion.get(j).consecuente[i] != 0.0) {
              num++;
            }
          }
          /* The term is NOT used in the consequent */
          else {
            Poblacion.get(j).consecuente[i] = 0.0;
          }
        }

        u = Randomize.RandClosed();
        /* The term is used in the consequent */
        if (u < 0.5) {
          //                    Poblacion.get(j).consecuente[entradas] = Randomize.RanddoubleClosed(
          // - 45.0, 45.0);
          Poblacion.get(j).consecuente[entradas] =
              Randomize.RanddoubleClosed(
                  -1.0 * ((train.getMax(entradas) - train.getMin(entradas)) / 2.0),
                  ((train.getMax(entradas) - train.getMin(entradas)) / 2.0));
          if (Poblacion.get(j).consecuente[entradas] != 0.0) {
            num++;
          }
        }
        /* The term is NOT used in the consequent */
        else {
          Poblacion.get(j).consecuente[entradas] = 0.0;
        }
      } while (num == 0);
    }
  }
示例#5
0
  /**
   * It Evaluates the performance of the best evolved fuzzy system on test data. The Mean Square
   * Error (MSE) is used
   *
   * @return double The MSE error in test data
   */
  public double Evaluate_best_fuzzy_system_in_test() {
    int i;
    double result, suma, fuerza;

    SistemaDifuso.clear();
    for (i = 0; i < Nr; i++) {
      Individual indi = new Individual(BestSistemaDifuso.get(i));
      SistemaDifuso.add(indi);
    }

    suma = 0.0;
    for (i = 0; i < test.getnData(); i++) {
      fuerza = Output_fuzzy_system(test.getExample(i));
      suma += Math.pow(test.getOutputAsReal(i) - fuerza, 2.0);
    }

    result = suma / test.getnData();

    return (result);
  }
示例#6
0
  /** It creates a fuzzy system containing Nr rules from the population */
  void Create_fuzzy_system() {
    int i, pos, tam;
    int[] vector = new int[tamPoblacion];

    for (i = 0; i < tamPoblacion; i++) {
      vector[i] = i;
    }
    tam = tamPoblacion;

    SistemaDifuso.clear();
    for (i = 0; i < Nr; i++) {
      pos = Randomize.RandintClosed(0, tam - 1);
      Poblacion.get(vector[pos]).n_SistemasDifusos++;
      Individual indi = new Individual(Poblacion.get(vector[pos]));
      SistemaDifuso.add(indi);
      vectorNr[i] = vector[pos];
      vector[pos] = vector[tam - 1];
      tam--;
    }
  }
示例#7
0
  /**
   * It calculate the output of the fuzzy system for a given example
   *
   * @param ejemplo double [] A given example
   * @return double The output value obtained as output of the fuzzy system for a given example
   */
  double Output_fuzzy_system(double[] ejemplo) {
    int i;
    double result, suma1, suma2, omega, y;

    suma1 = suma2 = 0.0;
    for (i = 0; i < Nr; i++) {
      omega = Matching_degree(SistemaDifuso.get(i), ejemplo);
      y = Output_value(SistemaDifuso.get(i), ejemplo);
      suma1 += (omega * y);
      suma2 += omega;
    }

    if (suma2 != 0.0) {
      result = suma1 / suma2;
    } else {
      //                result = 0.0;
      result = ((train.getMax(entradas) - train.getMin(entradas)) / 2.0);
    }

    return (result);
  }
示例#8
0
  /**
   * It reads the data from the input files (training, validation and test) and parse all the
   * parameters from the parameters array.
   *
   * @param parameters parseParameters It contains the input files, output files and parameters
   */
  public Algorithm(parseParameters parameters) {

    train = new myDataset();
    val = new myDataset();
    test = new myDataset();
    try {
      System.out.println("\nReading the training set: " + parameters.getTrainingInputFile());
      train.readRegressionSet(parameters.getTrainingInputFile(), true);
      System.out.println("\nReading the validation set: " + parameters.getValidationInputFile());
      val.readRegressionSet(parameters.getValidationInputFile(), false);
      System.out.println("\nReading the test set: " + parameters.getTestInputFile());
      test.readRegressionSet(parameters.getTestInputFile(), false);
    } catch (IOException e) {
      System.err.println("There was a problem while reading the input data-sets: " + e);
      somethingWrong = true;
    }

    // We may check if there are some numerical attributes, because our algorithm may not handle
    // them:
    // somethingWrong = somethingWrong || train.hasNumericalAttributes();
    // somethingWrong = somethingWrong || train.hasMissingAttributes();

    outputTr = parameters.getTrainingOutputFile();
    outputTst = parameters.getTestOutputFile();
    outputBC = parameters.getOutputFile(0);

    // Now we parse the parameters, for example:
    semilla = Long.parseLong(parameters.getParameter(0));
    // ...
    tamPoblacion = Integer.parseInt(parameters.getParameter(1));
    numGeneraciones = Integer.parseInt(parameters.getParameter(2));
    numGenMigration = Integer.parseInt(parameters.getParameter(3));
    Nr = Integer.parseInt(parameters.getParameter(4));
    Nf = Integer.parseInt(parameters.getParameter(5));
    K = Integer.parseInt(parameters.getParameter(6));
    probMut = Double.parseDouble(parameters.getParameter(7));

    entradas = train.getnInputs();

    Poblacion = new ArrayList<Individual>(tamPoblacion);
    for (int i = 0; i < tamPoblacion; i++) {
      Individual indi = new Individual(entradas);
      Poblacion.add(indi);
    }

    Poblacion2 = new ArrayList<Individual>(tamPoblacion);
    Hijos = new ArrayList<Individual>(tamPoblacion / 2);
    SistemaDifuso = new ArrayList<Individual>(Nr);
    BestSistemaDifuso = new ArrayList<Individual>(Nr);

    vectorNr = new int[Nr];
  }
示例#9
0
  public void removeRules() {
    int i, pos;
    double minRate, rate;
    Rule rule;

    minRate = 1.0;
    pos = -1;
    for (i = 0; i < this.ruleBase.size(); i++) {
      rule = this.ruleBase.get(i);
      if (rule.getRightN() < 1) {
        this.ruleBase.remove(i);
        i--;
      } else {
        rate = (1.0 * rule.getRightN()) / (1.0 * rule.getWrongN() + rule.getRightN());
        if (rate < minRate) {
          minRate = rate;
          pos = i;
        }
      }
    }

    if (ruleBase.size() > 0 && pos > -1) this.ruleBase.remove(pos);
  }
示例#10
0
  /**
   * It prints the current population as a String
   *
   * @return String The current population as a String
   */
  public String Print_Population() {
    int i, j, sig;
    double sigma, ancho_intervalo;
    boolean anterior_nulo;
    String output = new String("");

    output += "Rule Base with " + Nr + " rules\n\n";

    for (i = 0; i < Nr; i++) {
      output += "Rule " + (i + 1) + ": IF ";
      for (j = 0; j < entradas; j++) {
        ancho_intervalo = train.getMax(j) - train.getMin(j);

        sigma = -1.0;
        sig = BestSistemaDifuso.get(i).antecedente[j].sigma;
        switch (sig) {
          case 1:
            sigma = 0.3;
            break;
          case 2:
            sigma = 0.4;
            break;
          case 3:
            sigma = 0.5;
            break;
          case 4:
            sigma = 0.6;
            break;
        }

        sigma *= ancho_intervalo;

        output +=
            "X("
                + (j + 1)
                + ") is Gaussian("
                + BestSistemaDifuso.get(i).antecedente[j].m
                + ", "
                + sigma
                + ")";
        if (j != (entradas - 1)) {
          output += " and ";
        }
      }

      output += " THEN Y = ";

      anterior_nulo = true;
      if (BestSistemaDifuso.get(i).consecuente[entradas] != 0.0) {
        anterior_nulo = false;
        output += "(" + BestSistemaDifuso.get(i).consecuente[entradas] + ")";
      }

      for (j = 0; j < entradas; j++) {
        if (BestSistemaDifuso.get(i).consecuente[j] != 0.0) {
          if (anterior_nulo == false) {
            output += " + ";
          }

          anterior_nulo = false;
          output += "(" + BestSistemaDifuso.get(i).consecuente[j] + " * X(" + (j + 1) + "))";
        }
      }

      output += "\n\n";
    }

    return (output);
  }
示例#11
0
  /** It applies mutation genetic operator */
  void Mutation() {
    int i, j, aux1, num;
    double u, u2;

    for (j = 0; j < tamPoblacion; j++) {
      /* First, the antecedent */
      for (i = 0; i < entradas; i++) {
        u = Randomize.RandClosed();
        if (u < probMut) {
          Poblacion.get(j).antecedente[i].m =
              Randomize.RanddoubleClosed(train.getMin(i), train.getMax(i));
        }

        u = Randomize.RandClosed();
        if (u < probMut) {
          aux1 = Poblacion.get(j).antecedente[i].sigma;
          do {
            Poblacion.get(j).antecedente[i].sigma = Randomize.RandintClosed(1, 4);
          } while (aux1 == Poblacion.get(j).antecedente[i].sigma);
        }
      }

      /* Secondly, the consequent */
      num = 0;
      for (i = 0; i <= entradas; i++) {
        if (Poblacion.get(j).consecuente[i] != 0.0) {
          num++;
        }
      }

      for (i = 0; i < entradas; i++) {
        u = Randomize.RandClosed();
        if (u < probMut) {
          u2 = Randomize.RandClosed();
          if (u2 < 0.5) {
            Poblacion.get(j).consecuente[i] = Randomize.RanddoubleClosed(-1.0, 1.0);
          }
          /* The term is NOT used in the consequent */
          else {
            if (num != 1) {
              Poblacion.get(j).consecuente[i] = 0.0;
              num--;
            }
          }
        }
      }

      u = Randomize.RandClosed();
      if (u < probMut) {
        u2 = Randomize.RandClosed();
        if (u2 < 0.5) {
          Poblacion.get(j).consecuente[entradas] =
              Randomize.RanddoubleClosed(
                  -1.0 * ((train.getMax(entradas) - train.getMin(entradas)) / 2.0),
                  ((train.getMax(entradas) - train.getMin(entradas)) / 2.0));
          //                        Poblacion.get(j).consecuente[entradas] =
          // Randomize.RanddoubleClosed(-45.0, 45.0);
        }
        /* The term is NOT used in the consequent */
        else {
          if (num != 1) {
            Poblacion.get(j).consecuente[entradas] = 0.0;
            num--;
          }
        }
      }
    }
  }
示例#12
0
  /**
   * It applies a One-point Crossover genetic operator between individual in position "madre" and
   * "padre" in the population. The new generated children (2 descendants) are added in a population
   * of descendants
   *
   * @param madre int Parent number 1 is in position "madre" in the population
   * @param padre int Parent number 2 is in position "padre" in the population
   */
  void Crossover(int madre, int padre) {
    int i, xpoint, num1, num2;
    Individual Hijo1 = new Individual(entradas);
    Individual Hijo2 = new Individual(entradas);
    boolean salir;

    do {
      salir = true;

      /* We choose the crossover site */
      xpoint = Randomize.RandintClosed(1, ((2 * entradas) + entradas - 1));

      /* The crossover point is in the antededent part */
      if (xpoint < (2 * entradas)) {
        /* The crossover point does not part a fuzzy set */
        if ((xpoint % 2) == 0) {
          for (i = 0; i < (xpoint / 2); i++) {
            Hijo1.antecedente[i].m = Poblacion2.get(madre).antecedente[i].m;
            Hijo1.antecedente[i].sigma = Poblacion2.get(madre).antecedente[i].sigma;
            Hijo2.antecedente[i].m = Poblacion2.get(padre).antecedente[i].m;
            Hijo2.antecedente[i].sigma = Poblacion2.get(padre).antecedente[i].sigma;
          }
          for (i = (xpoint / 2); i < entradas; i++) {
            Hijo1.antecedente[i].m = Poblacion2.get(padre).antecedente[i].m;
            Hijo1.antecedente[i].sigma = Poblacion2.get(padre).antecedente[i].sigma;
            Hijo2.antecedente[i].m = Poblacion2.get(madre).antecedente[i].m;
            Hijo2.antecedente[i].sigma = Poblacion2.get(madre).antecedente[i].sigma;
          }
        }
        /* The crossover point part a fuzzy set */
        else {
          for (i = 0; i < ((xpoint - 1) / 2); i++) {
            Hijo1.antecedente[i].m = Poblacion2.get(madre).antecedente[i].m;
            Hijo1.antecedente[i].sigma = Poblacion2.get(madre).antecedente[i].sigma;
            Hijo2.antecedente[i].m = Poblacion2.get(padre).antecedente[i].m;
            Hijo2.antecedente[i].sigma = Poblacion2.get(padre).antecedente[i].sigma;
          }

          Hijo1.antecedente[((xpoint - 1) / 2)].m =
              Poblacion2.get(madre).antecedente[((xpoint - 1) / 2)].m;
          Hijo1.antecedente[((xpoint - 1) / 2)].sigma =
              Poblacion2.get(padre).antecedente[((xpoint - 1) / 2)].sigma;
          Hijo2.antecedente[((xpoint - 1) / 2)].m =
              Poblacion2.get(padre).antecedente[((xpoint - 1) / 2)].m;
          Hijo2.antecedente[((xpoint - 1) / 2)].sigma =
              Poblacion2.get(madre).antecedente[((xpoint - 1) / 2)].sigma;

          for (i = ((xpoint + 1) / 2); i < entradas; i++) {
            Hijo1.antecedente[i].m = Poblacion2.get(padre).antecedente[i].m;
            Hijo1.antecedente[i].sigma = Poblacion2.get(padre).antecedente[i].sigma;
            Hijo2.antecedente[i].m = Poblacion2.get(madre).antecedente[i].m;
            Hijo2.antecedente[i].sigma = Poblacion2.get(madre).antecedente[i].sigma;
          }
        }

        for (i = 0; i < (entradas + 1); i++) {
          Hijo1.consecuente[i] = Poblacion2.get(padre).consecuente[i];
          Hijo2.consecuente[i] = Poblacion2.get(madre).consecuente[i];
        }
      }
      /* The crossover point is in the consequent part */
      else {
        for (i = 0; i < entradas; i++) {
          Hijo1.antecedente[i].m = Poblacion2.get(madre).antecedente[i].m;
          Hijo1.antecedente[i].sigma = Poblacion2.get(madre).antecedente[i].sigma;
          Hijo2.antecedente[i].m = Poblacion2.get(padre).antecedente[i].m;
          Hijo2.antecedente[i].sigma = Poblacion2.get(padre).antecedente[i].sigma;
        }

        xpoint -= (2 * entradas);
        for (i = 0; i < xpoint; i++) {
          Hijo1.consecuente[i] = Poblacion2.get(madre).consecuente[i];
          Hijo2.consecuente[i] = Poblacion2.get(padre).consecuente[i];
        }
        for (i = xpoint; i < entradas; i++) {
          Hijo1.consecuente[i] = Poblacion2.get(padre).consecuente[i];
          Hijo2.consecuente[i] = Poblacion2.get(madre).consecuente[i];
        }
      }

      num1 = num2 = 0;
      for (i = 0; i <= entradas; i++) {
        if (Hijo1.consecuente[i] != 0) {
          num1++;
        }
        if (Hijo2.consecuente[i] != 0) {
          num2++;
        }
      }
      if ((num1 == 0) || (num2 == 0)) {
        salir = false;
      }
    } while (salir == false);

    /* Add the new 2 children to the offspring population */
    Hijos.add(Hijo1);
    Hijos.add(Hijo2);
  }
示例#13
0
  /** It applies the reproduction stage */
  void Reproduction() {
    int i, madre, padre;

    /* First, the individual in the population are ordered according to their fitness */
    Collections.sort(Poblacion);

    /* Create the new population */
    Poblacion2.clear();
    Hijos.clear();

    /* Top-half best-performing individuals will advance to the next generation */
    for (i = 0; i < (tamPoblacion / 2); i++) {
      Individual indi = new Individual(Poblacion.get(i));
      Poblacion2.add(indi);
    }

    /* The remaining half is generated by performing crossover operations on individuals
    in the top half */
    while (Poblacion.size() != (Poblacion2.size() + Hijos.size())) {
      /* 2 parents are selected */
      madre = Selection();
      do {
        padre = Selection();
      } while (madre == padre);

      /* 2 children are created by crossover operator */
      Crossover(madre, padre);
    }

    /* Create the population for the next generation */
    Poblacion.clear();
    for (i = 0; i < Poblacion2.size(); i++) {
      Individual indi = new Individual(Poblacion2.get(i));
      Poblacion.add(indi);
    }
    for (i = 0; i < Hijos.size(); i++) {
      Individual indi = new Individual(Hijos.get(i));
      Poblacion.add(indi);
    }
  }
示例#14
0
  /** It launches the algorithm */
  public void execute() {
    int i, j, num;
    double fitness, fitness2;

    if (somethingWrong) { // We do not execute the program
      System.err.println(
          "An error was found, either the data-set have numerical values or missing values.");
      System.err.println("Aborting the program");
      // We should not use the statement: System.exit(-1);
    } else {
      // We do here the algorithm's operations
      Randomize.setSeed(semilla);

      /* Generation of the initial population */
      System.out.println("Creating the initial population.");
      initializePopulation();
      Gen = 0;
      GenSincambio = 0;
      Bestperformance = -1.0;

      /* Main of the genetic algorithm */
      System.out.println("Starting the evolutionary process.");
      do {
        /* First, all rules' fitness is set to 0 */
        for (i = 0; i < tamPoblacion; i++) {
          Poblacion.get(i).fitness = 0.0;
          Poblacion.get(i).n_SistemasDifusos = 0;
        }

        /* Then Nf fuzzy system are created */
        for (i = 0; i < Nf; i++) {
          /* A fuzzy system containing Nr rules from the population is created */
          Create_fuzzy_system();

          /* The fitness asociated to this fuzzy system is calculated */
          fitness = Evaluate_fuzzy_system();

          /* The fitness value is accumulated among the rules in the fuzzy system */
          Accumulate_fitness_fuzzy_system(fitness);

          /* If the fitness of the current fuzzy system outperforms the best evolved one,
          we update this last one */
          if (fitness > Bestperformance) {
            Bestperformance = fitness;
            GenSincambio = -1;

            BestSistemaDifuso.clear();
            for (j = 0; j < Nr; j++) {
              Individual indi = new Individual(Poblacion.get(vectorNr[j]));
              BestSistemaDifuso.add(indi);
            }
          }
        }

        /* The accumulated fitness value of each individual in the population is divided
        by the number of times it has been selected */
        for (i = 0; i < tamPoblacion; i++) {
          if (Poblacion.get(i).n_SistemasDifusos != 0) {
            Poblacion.get(i).fitness /= Poblacion.get(i).n_SistemasDifusos;
          } else {
            Poblacion.get(i).fitness = 0.0;
          }

          /* Now we count the number of parameter used in the consequent, in order to
          give a better fitness to those rules with a lower number of parameters */
          num = 0;
          for (j = 0; j < entradas; j++) {
            if (Poblacion.get(i).consecuente[j] != 0.0) {
              num++;
            }
          }
          if (Poblacion.get(i).consecuente[entradas] != 0.0) {
            num++;
          }

          Poblacion.get(i).fitness /= (K + num);
        }

        /* we increment the counter of the number of generations */
        Gen++;
        GenSincambio++;

        if (GenSincambio == numGenMigration) {
          /* Migration stage: half of the population (the worst one) is radomly generated again
          to increase the searching ability of the genetic process */
          System.out.println(
              "Migrating half of the population in order to restart the evolutionary process.");
          Migration();
          GenSincambio = 0;
        } else {
          /* Reproduction stage (includes crossover) */
          Reproduction();

          /* Mutation */
          Mutation();
        }
        System.out.println("Iteration: " + Gen + ". Best fitness: " + (1.0 / Bestperformance));
      } while (Gen <= numGeneraciones);

      String salida = new String("");
      salida += Print_Population();

      SistemaDifuso.clear();
      for (i = 0; i < Nr; i++) {
        Individual indi = new Individual(BestSistemaDifuso.get(i));
        SistemaDifuso.add(indi);
      }

      salida += "MSE Training:\t" + (1.0 / Bestperformance) + "%\n";
      salida += "MSE Test:\t\t" + Evaluate_best_fuzzy_system_in_test() + "%\n\n";

      Files.writeFile(outputBC, salida);

      doOutput(this.val, this.outputTr);
      doOutput(this.test, this.outputTst);

      System.out.println("Algorithm Finished.");
    }
  }