All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.ericmedvet.jgea.experimenter.builders.NamedFunctions Maven / Gradle / Ivy

There is a newer version: 2.7.0
Show newest version
/*
 * Copyright 2022 eric
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.github.ericmedvet.jgea.experimenter.builders;

import io.github.ericmedvet.jgea.core.listener.NamedFunction;
import io.github.ericmedvet.jgea.core.solver.Individual;
import io.github.ericmedvet.jgea.core.solver.state.POSetPopulationState;
import io.github.ericmedvet.jgea.core.solver.state.State;
import io.github.ericmedvet.jgea.core.util.Misc;
import io.github.ericmedvet.jgea.core.util.TextPlotter;
import io.github.ericmedvet.jnb.core.Param;
import io.github.ericmedvet.jnb.core.ParamMap;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.*;
import java.util.function.Function;
import java.util.logging.Logger;

public class NamedFunctions {

  private final static Logger L = Logger.getLogger(NamedFunctions.class.getName());

  private NamedFunctions() {
  }

  public enum Op {
    PLUS("+"), MINUS("-"), PROD("*"), DIV("/");
    private final String rendered;

    Op(String rendered) {
      this.rendered = rendered;
    }
  }

  @SuppressWarnings("unused")
  public static  NamedFunction, Collection>> all() {
    return NamedFunction.build("all", s -> s.getPopulation().all());
  }

  @SuppressWarnings("unused")
  public static  NamedFunction base64(
      @Param("f") NamedFunction f
  ) {
    return NamedFunction.build(c("base64", f.getName()), x -> {
      try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(
          baos)) {
        oos.writeObject(f.apply(x));
        oos.flush();
        return Base64.getEncoder().encodeToString(baos.toByteArray());
      } catch (Throwable t) {
        L.warning("Cannot serialize %s due to %s".formatted(f.getName(), t));
        return "not-serializable";
      }
    });
  }

  @SuppressWarnings("unused")
  public static  NamedFunction, Individual> best() {
    return NamedFunction.build("best", s -> Misc.first(s.getPopulation().firsts()));
  }

  @SuppressWarnings("unused")
  public static  NamedFunction, T> bestFitness(
      @Param(value = "f", dNPM = "ea.nf.identity()") NamedFunction function,
      @Param(value = "s", dS = "%s") String s
  ) {
    return NamedFunction.build(
        c(function.getName(), "fitness", "best"),
        s.equals("%s") ? function.getFormat() : s,
        state -> function.apply(Objects.requireNonNull(Misc.first(state.getPopulation().firsts())).fitness())
    );
  }

  @SuppressWarnings("unused")
  public static NamedFunction, Long> births() {
    return NamedFunction.build("births", "%6d", POSetPopulationState::getNOfBirths);
  }

  private static String c(String... names) {
    return Arrays.stream(names).reduce(NamedFunction.NAME_COMPOSER::apply).orElseThrow();
  }

  @SuppressWarnings("unused")
  public static  NamedFunction> each(
      @Param("map") NamedFunction mapF,
      @Param("collection") NamedFunction> collectionF,
      @Param(value = "s", dS = "%s") String s
  ) {
    return NamedFunction.build(
        c("each[%s]".formatted(mapF.getName()), collectionF.getName()),
        s,
        x -> collectionF.apply(x).stream().map(mapF).toList()
    );
  }

  @SuppressWarnings("unused")
  public static NamedFunction, Double> elapsed() {
    return NamedFunction.build("elapsed.seconds", "%5.1f", s -> s.getElapsedMillis() / 1000d);
  }

  @SuppressWarnings("unused")
  public static NamedFunction, Long> evals() {
    return NamedFunction.build("evals", "%6d", POSetPopulationState::getNOfFitnessEvaluations);
  }

  @SuppressWarnings("unused")
  public static  NamedFunction expr(
      @Param("f1") NamedFunction f1, @Param("f2") NamedFunction f2, @Param("op") Op op
  ) {
    return NamedFunction.build(
        "%s%s%s".formatted(f1.getName(), op.rendered, f2.getName()),
        f1.getFormat(),
        x -> switch (op) {
          case PLUS -> f1.apply(x).doubleValue() + f2.apply(x).doubleValue();
          case MINUS -> f1.apply(x).doubleValue() - f2.apply(x).doubleValue();
          case PROD -> f1.apply(x).doubleValue() * f2.apply(x).doubleValue();
          case DIV -> f1.apply(x).doubleValue() / f2.apply(x).doubleValue();
        }
    );
  }

  @SuppressWarnings("unused")
  public static  NamedFunction f(
      @Param("outerF") Function outerFunction,
      @Param(value = "innerF", dNPM = "ea.nf.identity()") NamedFunction innerFunction,
      @Param("name") String name,
      @Param(value = "s", dS = "%s") String s,
      @Param(value = "", injection = Param.Injection.MAP) ParamMap map
  ) {
    if ((name == null) || name.isEmpty()) {
      name = map.npm("outerF").getName();
    }
    return NamedFunction.build(c(name, innerFunction.getName()), s, x -> outerFunction.apply(innerFunction.apply(x)));
  }

  @SuppressWarnings("unused")
  public static  NamedFunction, Collection>> firsts() {
    return NamedFunction.build("firsts", s -> s.getPopulation().firsts());
  }

  @SuppressWarnings("unused")
  public static  NamedFunction fitness(
      @Param(value = "individual", dNPM = "ea.nf.identity()") NamedFunction> individualF,
      @Param(value = "s", dS = "%s") String s
  ) {
    return NamedFunction.build(c("fitness", individualF.getName()), s, x -> individualF.apply(x).fitness());
  }

  @SuppressWarnings("unused")
  public static  NamedFunction, String> fitnessHist(
      @Param(value = "f", dNPM = "ea.nf.identity()") NamedFunction function,
      @Param(value = "nBins", dI = 8) int nBins
  ) {
    return NamedFunction.build(
        c("hist", "each[%s]".formatted(c(function.getName(), "fitness")), "all"),
        "%" + nBins + "." + nBins + "s",
        state -> {
          List numbers = state.getPopulation().all().stream().map(i -> function.apply(i.fitness())).toList();
          return TextPlotter.histogram(numbers, nBins);
        }
    );
  }

  @SuppressWarnings("unused")
  public static  NamedFunction formatted(
      @Param("s") String s, @Param("f") NamedFunction f
  ) {
    return f.reformat(s);
  }

  @SuppressWarnings("unused")
  public static  NamedFunction genotype(
      @Param(value = "individual", dNPM = "ea.nf.identity()") NamedFunction> individualF,
      @Param(value = "s", dS = "%s") String s
  ) {
    return NamedFunction.build(c("genotype", individualF.getName()), s, x -> individualF.apply(x).genotype());
  }

  @SuppressWarnings("unused")
  public static  NamedFunction hist(
      @Param("collection") NamedFunction> collectionF, @Param(value = "nBins", dI = 8) int nBins
  ) {
    return NamedFunction.build(c("hist", collectionF.getName()), "%" + nBins + "." + nBins + "s", x -> {
      Collection collection = collectionF.apply(x);
      return TextPlotter.histogram(collection instanceof List list ? list : new ArrayList<>(collection), nBins);
    });
  }

  @SuppressWarnings("unused")
  public static  NamedFunction identity() {
    return NamedFunction.build("", t -> t);
  }

  @SuppressWarnings("unused")
  public static NamedFunction, Long> iterations() {
    return NamedFunction.build("iterations", "%3d", State::getNOfIterations);
  }

  @SuppressWarnings("unused")
  public static  NamedFunction, Collection>> lasts() {
    return NamedFunction.build("lasts", s -> s.getPopulation().lasts());
  }

  @SuppressWarnings("unused")
  public static > NamedFunction max(
      @Param("collection") NamedFunction> collectionF, @Param(value = "s", dS = "%s") String s
  ) {
    return NamedFunction.build(c("max", collectionF.getName()), s, x -> {
      List collection = collectionF.apply(x).stream().sorted().toList();
      return collectionF.apply(x).stream().max(Comparable::compareTo).orElse(null);
    });
  }

  @SuppressWarnings("unused")
  public static > NamedFunction median(
      @Param("collection") NamedFunction> collectionF, @Param(value = "s", dS = "%s") String s
  ) {
    return percentile(collectionF, 0.5, s);
  }

  @SuppressWarnings("unused")
  public static > NamedFunction min(
      @Param("collection") NamedFunction> collectionF, @Param(value = "s", dS = "%s") String s
  ) {
    return NamedFunction.build(c("min", collectionF.getName()), s, x -> {
      List collection = collectionF.apply(x).stream().sorted().toList();
      return collectionF.apply(x).stream().min(Comparable::compareTo).orElse(null);
    });
  }

  @SuppressWarnings("unused")
  public static > NamedFunction percentile(
      @Param("collection") NamedFunction> collectionF,
      @Param("p") double p,
      @Param(value = "s", dS = "%s") String s
  ) {
    return NamedFunction.build(c("perc[%2d]".formatted((int) Math.round(p * 100)), collectionF.getName()), s, x -> {
      List collection = collectionF.apply(x).stream().sorted().toList();
      int i = (int) Math.max(Math.min(((double) collection.size()) * p, collection.size() - 1), 0);
      return collection.get(i);
    });
  }

  @SuppressWarnings("unused")
  public static NamedFunction, Double> progress() {
    return NamedFunction.build("progress", "%4.2f", s -> s.getProgress().rate());
  }

  @SuppressWarnings("unused")
  public static  NamedFunction size(
      @Param("f") NamedFunction f, @Param(value = "s", dS = "%s") String s
  ) {
    return NamedFunction.build(
        c("size", f.getName()),
        s,
        x -> io.github.ericmedvet.jgea.core.listener.NamedFunctions.size(f.apply(x))
    );
  }

  @SuppressWarnings("unused")
  public static  NamedFunction solution(
      @Param(value = "individual", dNPM = "ea.nf.identity()") NamedFunction> individualF,
      @Param(value = "s", dS = "%s") String s
  ) {
    return NamedFunction.build(c("solution", individualF.getName()), s, x -> individualF.apply(x).solution());
  }

  @SuppressWarnings("unused")
  public static  NamedFunction uniqueness(
      @Param("collection") NamedFunction> collectionF
  ) {
    return NamedFunction.build(c("uniqueness", collectionF.getName()), "%4.2f", x -> {
      Collection collection = collectionF.apply(x);
      return ((double) (new HashSet<>(collection).size())) / ((double) collection.size());
    });
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy