jMetal解説 - Problem interface

##元のページ
https://github.com/jMetal/jMetalDocumentation/blob/master/problem.md

これを雑に日本語にしただけ．
以下本文．


##The `Problem` interface

問題を表現するクラスは，`Problem`インターフェースをimplementする．

```java
package org.uma.jmetal.problem;

/**
 * Interface representing a multi-objective optimization problem
 *
 * @author Antonio J. Nebro <antonio@lcc.uma.es>
 *
 * @param <S> Encoding
 */
public interface Problem<S extends Solution<?>> extends Serializable {
  /* Getters */
  public int getNumberOfVariables() ;
  public int getNumberOfObjectives() ;
  public int getNumberOfConstraints() ;
  public String getName() ;

  /* Methods */
  public void evaluate(S solution) ;
  public S createSolution() ;
```


Problemは決定変数の数，目的関数の数，制約の数で特徴付けられる．
そのため，それぞれの値を取得するためのgetterメソッドが定義されている．
仮想パラメータ`S`は解のエンコーディングを決定する．
`evaluate()`はクラス`S`の解を評価するメソッド，`createSolution()`は新しい解を生成するメソッドである．

`Solution`インターフェースはジェネリック型なので，
jMetal5には連続値問題や，2値問題を表すための`Solution`を拡張したインターフェースが多数存在する．
例えば，`DoubleProblem`インターフェースは以下のように定義されている．

```java
package org.uma.jmetal.problem;

/**
 * Interface representing continuous problems
 *
 * @author Antonio J. Nebro <antonio@lcc.uma.es>
 */
public interface DoubleProblem extends Problem<DoubleSolution> {
  Double getLowerBound(int index) ;
  Double getUpperBound(int index) ;
}
```

`DoubleProblem`を実装したクラスは，`DoubleSolution`のみを受け付ける．
そして，各変数の下限値と上限値を取得するgetterメソッドを実装する必要がある．
jMetal5では，`DoubleProblem`を実装したデフォルトのabstract classとして`AbstractDoubleProblem`が用意されている．


```java
package org.uma.jmetal.problem.impl;

public abstract class AbstractDoubleProblem extends AbstractGenericProblem<DoubleSolution>
  implements DoubleProblem {

  private List<Double> lowerLimit ;
  private List<Double> upperLimit ;

  /* Getters */
  @Override
  public Double getUpperBound(int index) {
    return upperLimit.get(index);
  }

  @Override
  public Double getLowerBound(int index) {
    return lowerLimit.get(index);
  }

  /* Setters */
  protected void setLowerLimit(List<Double> lowerLimit) {
    this.lowerLimit = lowerLimit;
  }

  protected void setUpperLimit(List<Double> upperLimit) {
    this.upperLimit = upperLimit;
  }

  @Override
  public DoubleSolution createSolution() {
    return new DefaultDoubleSolution(this)  ;
  }
}
```

連続値問題の例として，次のように[`Kursawa`](https://github.com/jMetal/jMetal/blob/jmetal-5.0/jmetal-problem/src/main/java/org/uma/jmetal/problem/multiobjective/Kursawe.java)問題が実装されている．

```java
package org.uma.jmetal.problem.multiobjective;

/**
 * Class representing problem Kursawe
 */
public class Kursawe extends AbstractDoubleProblem {

  /**
   * Constructor.
   * Creates a default instance of the Kursawe problem.
   */
  public Kursawe() {
    // 3 variables by default
    this(3);
  }

  /**
   * Constructor.
   * Creates a new instance of the Kursawe problem.
   *
   * @param numberOfVariables Number of variables of the problem
   */
  public Kursawe(Integer numberOfVariables) {
    setNumberOfVariables(numberOfVariables);
    setNumberOfObjectives(2);
    setName("Kursawe");

    List<Double> lowerLimit = new ArrayList<>(getNumberOfVariables()) ;
    List<Double> upperLimit = new ArrayList<>(getNumberOfVariables()) ;

    for (int i = 0; i < getNumberOfVariables(); i++) {
      lowerLimit.add(-5.0);
      upperLimit.add(5.0);
    }

    setLowerLimit(lowerLimit);
    setUpperLimit(upperLimit);
  }

  /** Evaluate() method */
  public void evaluate(DoubleSolution solution){
    double aux, xi, xj;
    double[] fx = new double[getNumberOfObjectives()];
    double[] x = new double[getNumberOfVariables()];
    for (int i = 0; i < solution.getNumberOfVariables(); i++) {
      x[i] = solution.getVariableValue(i) ;
    }

    fx[0] = 0.0;
    for (int var = 0; var < solution.getNumberOfVariables() - 1; var++) {
      xi = x[var] * x[var];
      xj = x[var + 1] * x[var + 1];
      aux = (-0.2) * Math.sqrt(xi + xj);
      fx[0] += (-10.0) * Math.exp(aux);
    }

    fx[1] = 0.0;

    for (int var = 0; var < solution.getNumberOfVariables(); var++) {
      fx[1] += Math.pow(Math.abs(x[var]), 0.8) +
        5.0 * Math.sin(Math.pow(x[var], 3.0));
    }

    solution.setObjective(0, fx[0]);
    solution.setObjective(1, fx[1]);
  }
}
```

`DoubleProblem`インターフェースと`AbstractDoubleProblem`と同様に，
`BinaryProblem`と`AbstractBinaryProblem`，
`IntegerProblem`と`AbstractIntegerProblem`が定義されている．

+ (`org.uma.jmetal.problem` (module `jmetal-core`))[]: インターフェースの定義．
+ (`org.uma.jmetal.problem.impl` (module `jmetal-core`):)[]: デフォルトの実装．
+ (`org.uma.jmetal.problem` (module `jmetal-problem`):)[]: 実装された問題．



### 制約付き問題
jMetal5で制約付き問題を扱う方法は2種類ある．
1. `evaluate()`メソッド内で制約違反を処理する．
2. 制約を評価するメソッドを持つ`ConstrainedProblem`インターフェースを実装する．

```java
package org.uma.jmetal.problem;

/**
 * Interface representing problems having constraints
 *
 * @author Antonio J. Nebro <antonio@lcc.uma.es>
 */
public interface ConstrainedProblem<S extends Solution<?>> extends Problem<S> {

 /* Getters */
  public int getNumberOfConstraints() ;
	
  /* Methods */
  public void evaluateConstraints(S solution) ;
}
```

jMetal5では普通，後者のアプローチをとる．
例として，以下は2つの制約を持つ[`Tanaka`]()問題である．

```java
package org.uma.jmetal.problem.multiobjective;

/**
 * Class representing problem Tanaka
 */
public class Tanaka extends AbstractDoubleProblem implements ConstrainedProblem<DoubleSolution> {
  public OverallConstraintViolation<DoubleSolution> overallConstraintViolationDegree ;
  public NumberOfViolatedConstraints<DoubleSolution> numberOfViolatedConstraints ;

  /**
   * Constructor.
   * Creates a default instance of the problem Tanaka
   */
  public Tanaka() {
    setNumberOfVariables(2);
    setNumberOfObjectives(2);
    setNumberOfConstraints(2);
    setName("Tanaka") ;

    List<Double> lowerLimit = new ArrayList<>(getNumberOfVariables()) ;
    List<Double> upperLimit = new ArrayList<>(getNumberOfVariables()) ;

    for (int i = 0; i < getNumberOfVariables(); i++) {
      lowerLimit.add(10e-5);
      upperLimit.add(Math.PI);
    }

    setLowerLimit(lowerLimit);
    setUpperLimit(upperLimit);

    overallConstraintViolationDegree = new OverallConstraintViolation<DoubleSolution>() ;
    numberOfViolatedConstraints = new NumberOfViolatedConstraints<DoubleSolution>() ;
  }

  @Override
  public void evaluate(DoubleSolution solution)  {
    solution.setObjective(0, solution.getVariableValue(0));
    solution.setObjective(1, solution.getVariableValue(1));
  }

  /** EvaluateConstraints() method */
  @Override
  public void evaluateConstraints(DoubleSolution solution)  {
    double[] constraint = new double[this.getNumberOfConstraints()];

    double x1 = solution.getVariableValue(0) ;
    double x2 = solution.getVariableValue(1) ;

    constraint[0] = (x1 * x1 + x2 * x2 - 1.0 - 0.1 * Math.cos(16.0 * Math.atan(x1 / x2)));
    constraint[1] = -2.0 * ((x1 - 0.5) * (x1 - 0.5) + (x2 - 0.5) * (x2 - 0.5) - 0.5);

    double overallConstraintViolation = 0.0;
    int violatedConstraints = 0;
    for (int i = 0; i < getNumberOfConstraints(); i++) {
      if (constraint[i]<0.0){
        overallConstraintViolation+=constraint[i];
        violatedConstraints++;
      }
    }

    overallConstraintViolationDegree.setAttribute(solution, overallConstraintViolation);
    numberOfViolatedConstraints.setAttribute(solution, violatedConstraints);
  }
}
```

###Discusion
`ConstrainedProblem`インターフェースを組み込むことは，
以前のバージョンですべての問題が`evaluate()`と`evaluateConstraints()`を持っていたことに動機付けられている．
制約のない問題では`evaluateConstraints()`はからのメソッドとして実装されていた．
Interface Segregation Principle違反を回避するために，jMetal5では制約が必要な問題だけ，制約を評価する．

元のjMetalでは以下のように解の評価が2回必要だった．

```java
Problem problem ;
Solution solution ;
...
problem.evaluate(solution) ;
problem.evaluateContraints(solution) ;
```

現在のバージョンでは，制約があるかどうかのチェックが含まれていなければならない．

```java
Problem problem ;
Solution solution ;
...
problem.evaluate(solution) ;
problem.evaluateContraints(solution) ;

```