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

com.github.dakusui.jcunit8.factorspace.Parameter Maven / Gradle / Ivy

There is a newer version: 0.8.17
Show newest version
package com.github.dakusui.jcunit8.factorspace;

import com.github.dakusui.jcunit.core.tuples.Tuple;
import com.github.dakusui.jcunit.exceptions.InvalidTestException;
import com.github.dakusui.jcunit.fsm.FiniteStateMachine;
import com.github.dakusui.jcunit.fsm.spec.FsmSpec;
import com.github.dakusui.jcunit.regex.Expr;
import com.github.dakusui.jcunit.regex.Parser;
import com.github.dakusui.jcunit.regex.RegexComposer;
import com.github.dakusui.jcunit8.core.Utils;
import com.github.dakusui.jcunit8.factorspace.fsm.FsmComposer;
import com.github.dakusui.jcunit8.factorspace.fsm.FsmDecomposer;
import com.github.dakusui.jcunit8.factorspace.fsm.Scenario;
import com.github.dakusui.jcunit8.factorspace.regex.RegexDecomposer;

import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;

import static com.github.dakusui.jcunit8.exceptions.TestDefinitionException.checkValue;
import static java.util.Collections.*;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;

/**
 * A user level factor.
 *
 * @param  Type of values held by this class.
 */
public interface Parameter {
  String getName();

  FactorSpace toFactorSpace();

  T composeValue(Tuple tuple);

  Optional decomposeValue(T value);

  List getKnownValues();

  abstract class Base implements Parameter {
    protected final String  name;
    private final   List knownValues;

    protected Base(String name, List knownValues) {
      this.name = requireNonNull(name);
      this.knownValues = unmodifiableList(requireNonNull(knownValues));
    }

    @Override
    public String getName() {
      return this.name;
    }

    @Override
    public FactorSpace toFactorSpace() {
      return FactorSpace.create(decompose(), generateConstraints());
    }

    @Override
    public List getKnownValues() {
      return this.knownValues;
    }

    protected abstract List decompose();

    protected abstract List generateConstraints();

    static  Optional _decomposeValue(V value, Stream tuples, Function valueComposer, Predicate constraints) {
      AtomicReference> fallback = new AtomicReference<>(Optional.empty());
      return tuples.filter(
          (Tuple tuple) -> {
            return value.equals(valueComposer.apply(tuple));
          }
      ).filter(
          constraints
      ).findFirst(
      );
    }
  }

  interface Factory {
    > F addActualValue(T actualValue);

    > F addActualValues(List actualValues);

    Parameter create(String name);

    abstract class Base implements Factory {

      protected final List knownValues = new LinkedList<>();

      @SuppressWarnings("unchecked")
      @Override
      public > F addActualValue(T actualValue) {
        knownValues.add(actualValue);
        return (F) this;
      }

      @SuppressWarnings("unchecked")
      @Override
      public > F addActualValues(List actualValues) {
        actualValues.forEach(this::addActualValue);
        return (F) this;
      }
    }
  }

  interface Simple extends Parameter {
    class Impl extends Base implements Simple {
      final Factor factor;

      public Impl(String name, List allLevels) {
        super(name, allLevels);
        this.factor = Factor.create(name, allLevels.toArray());
      }

      @Override
      protected List decompose() {
        return singletonList(factor);
      }

      @Override
      protected List generateConstraints() {
        return emptyList();
      }

      @SuppressWarnings("unchecked")
      @Override
      public T composeValue(Tuple tuple) {
        return (T) tuple.get(getName());
      }

      @Override
      public Optional decomposeValue(T value) {
        return Optional.of(Tuple.builder().put(name, value).build());
      }

      @Override
      public String toString() {
        return String.format("Simple:%s:%s", factor.getName(), factor.getLevels());
      }
    }

    class Factory extends Parameter.Factory.Base {

      private Factory() {
      }

      public static  Factory of(List actualValues) {
        return new Factory().addActualValues(actualValues);
      }

      @Override
      public Parameter create(String name) {
        return new Impl<>(name, this.knownValues);
      }
    }
  }

  interface Regex extends Parameter> {
    class Impl extends Parameter.Base> implements Regex {

      private final FactorSpace         factorSpace;
      private final RegexComposer       regexComposer;
      private final Function func;

      public Impl(String name, String regex, List> knownValues, Function func) {
        super(name, knownValues);
        Expr expr = new Parser().parse(regex);
        RegexDecomposer translator = new RegexDecomposer(name, expr);
        this.func = func;
        this.regexComposer = new RegexComposer(name, expr);
        this.factorSpace = translator.decompose();
      }

      public Optional decomposeValue(List value) {
        return _decomposeValue(
            value,
            this.factorSpace.stream(),
            this.regexComposer::compose,
            Utils.conjunct(this.factorSpace.getConstraints())
        );
      }

      @Override
      public List composeValue(Tuple tuple) {
        return composeStringValueFrom(tuple).stream().map(func).collect(toList());
      }

      @Override
      protected List decompose() {
        return factorSpace.getFactors();
      }

      @Override
      protected List generateConstraints() {
        return factorSpace.getConstraints();
      }

      private List composeStringValueFrom(Tuple tuple) {
        return regexComposer.compose(tuple);
      }
    }

    class Factory extends Parameter.Factory.Base> {
      private final String              regex;
      private final Function func;

      @Override
      public Regex create(String name) {
        return create(name, regex, knownValues, func);
      }

      public static  Factory of(String regex, Function func) {
        return new Factory<>(regex, func);
      }

      public static Factory of(String regex) {
        return new Factory<>(regex, s -> s);
      }

      private Factory(String regex, Function func) {
        this.regex = requireNonNull(regex);
        this.func = requireNonNull(func);
      }

      private static  Regex create(String name, String regex, List> knownValues, Function func) {
        return new Impl<>(name, regex, knownValues, func);
      }
    }
  }

  interface Fsm extends Parameter> {
    class Impl extends Parameter.Base> implements Fsm {
      private final FsmComposer composer;
      private final FactorSpace      factorSpace;

      Impl(String name, FiniteStateMachine model, List> knownValues, int scenarioLength) {
        super(name, knownValues);
        FsmDecomposer decomposer = new FsmDecomposer<>(name, model, scenarioLength);
        this.composer = new FsmComposer<>(name, model, scenarioLength);
        this.factorSpace = FactorSpace.create(decomposer.getFactors(), decomposer.getConstraints());
      }

      @Override
      public Optional decomposeValue(Scenario value) {
        return _decomposeValue(
            value,
            this.factorSpace.stream(),
            tuple -> {
              try {
                return this.composer.composeValueFrom(tuple);
              } catch (InvalidTestException e) {
                return false;
              }
            },
            Utils.conjunct(this.factorSpace.getConstraints())
        );
      }

      @Override
      public Scenario composeValue(Tuple tuple) {
        return composer.composeValueFrom(tuple);
      }

      @Override
      protected List decompose() {
        return factorSpace.getFactors();
      }

      @Override
      protected List generateConstraints() {
        return factorSpace.getConstraints();
      }
    }

    class Factory extends Parameter.Factory.Base> {
      private final Class> fsmSpecClass;
      private       int                           scenarioLength;

      @Override
      public Fsm create(String name) {
        return new Impl<>(
            name,
            new FiniteStateMachine.Impl<>(name, this.fsmSpecClass),
            knownValues,
            scenarioLength
        );
      }

      public Factory(Class> fsmSpecClass, int scenarioLength) {
        this.fsmSpecClass = requireNonNull(fsmSpecClass);
        this.scenarioLength = checkValue(scenarioLength, (Integer value) -> value > 0);
      }

      public static  Factory of(Class> fsmSpecClass, int scenarioLength) {
        return new Factory<>(fsmSpecClass, scenarioLength);
      }
    }
  }
}