private void calculateAbsoluteAverages(PSO pso) {

    int dimension = pso.getTopology().last().getDimension();
    absoluteAverageVelocityVector = Vector.of();
    averageSpeedVector = Vector.of();

    for (Entity e : pso.getTopology()) {
      Vector velocity = (Vector) e.getProperties().get(EntityType.Particle.VELOCITY);
      for (int i = 0; i < dimension; i++) {
        if (absoluteAverageVelocityVector.size() < dimension) {
          absoluteAverageVelocityVector.add(velocity.get(i));
          averageSpeedVector.add(Real.valueOf(Math.abs(velocity.doubleValueOf(i))));
        } else {
          absoluteAverageVelocityVector.setReal(
              i, absoluteAverageVelocityVector.doubleValueOf(i) + velocity.doubleValueOf(i));
          averageSpeedVector.setReal(
              i, averageSpeedVector.doubleValueOf(i) + Math.abs(velocity.doubleValueOf(i)));
        }
      }
    }

    for (int i = 0; i < dimension; i++) {
      absoluteAverageVelocityVector.setReal(
          i, Math.abs(absoluteAverageVelocityVector.doubleValueOf(i) / (double) dimension));
      averageSpeedVector.setReal(i, averageSpeedVector.doubleValueOf(i) / (double) dimension);
    }
  }
  /** Test the get column method. */
  @Test
  public void testGetColumn() {
    TypeList expected = new TypeList();
    expected.add(Real.valueOf(0.2));
    expected.add(Real.valueOf(1.2));
    TypeList column = stringTargetPatterns.getColumn(1);
    Assert.assertEquals(expected, column);

    expected = new TypeList();
    Vector target = Vector.of(1, 1, 0);
    expected.add(target);
    target = Vector.of(0, 0, 1);
    expected.add(target);
    column = vectorTargetPatterns.getColumn(5);
    Assert.assertEquals(expected, column);
  }
Ejemplo n.º 3
0
  /**
   * Given the datatype key, determines the datatype for a given column. Also sets up the HashTables
   * to map a nominal attribute to a corresponding integer number.
   *
   * @param columnn the column to map to a datatype.
   * @param datatype the datatype key.
   * @return a corresponding CIlib type.
   * @throws CIlibIOException {@inheritDoc}
   */
  private Type getTypeData(int columnn, String datatype) throws CIlibIOException {
    if (datatype.equalsIgnoreCase("NUMERIC")) {
      return Real.valueOf(0.0);
    }
    if (datatype.equalsIgnoreCase("STRING")) {
      return new StringType("");
    }
    if (datatype.equalsIgnoreCase("DATE")) {
      throw new UnsupportedOperationException("Date format currently not supported" + " in CIlib.");
    }

    // If none of the above, has to be a nominal attribute.
    if (columnToNominalAttributesMap == null) {
      columnToNominalAttributesMap = new HashMap<Integer, HashMap<String, Integer>>();
    }
    HashMap<String, Integer> nominalMap = new HashMap<String, Integer>();
    datatype = datatype.replaceAll("[{}]", "");
    String[] nominalAttributes = datatype.split("\\,");
    if (nominalAttributes.length == 0) {
      throw new CIlibIOException(
          "Nominal attributes must be comma separated:"
              + "{<nominal-name1>, <nominal-name2>, <nominal-name3>, ...} ");
    }
    for (int i = 0; i < nominalAttributes.length; i++) {
      String nominalAttribute = nominalAttributes[i];
      nominalMap.put(nominalAttribute, i);
    }
    columnToNominalAttributesMap.put(columnn, nominalMap);
    return Int.valueOf(0);
  }
  @Test
  public void testSetColumn() {
    TypeList newColumn = new TypeList();
    List<Real> list = Arrays.asList(Real.valueOf(5.2), Real.valueOf(6.2));
    for (Real real : list) {
      newColumn.add(real);
    }
    stringTargetPatterns.setColumn(0, newColumn);
    Assert.assertEquals(newColumn, stringTargetPatterns.getColumn(0));

    newColumn = new TypeList();
    Vector target = Vector.of(1, 1, 0);
    newColumn.add(target);
    target = Vector.of(0, 0, 1);
    newColumn.add(target);
    newColumn = vectorTargetPatterns.getColumn(5);
    Assert.assertEquals(newColumn, vectorTargetPatterns.getColumn(5));
  }
Ejemplo n.º 5
0
 @Override
 public List<Type> nextRow() {
   List<Type> row = Lists.newArrayList();
   for (int i = 0; i < this.columnCount; ++i) {
     row.add(Real.valueOf(this.vector.get(this.index + i).doubleValue()));
   }
   this.index += this.columnCount;
   return row;
 }
Ejemplo n.º 6
0
  @BeforeClass
  public static void setUpBeforeClass() throws Exception {
    Vector.Builder tmp = Vector.newBuilder();
    set = new ArrayList<Pattern>();

    for (int i = 1; i <= SIZE; i++) {
      tmp.add(Real.valueOf(i));
    }
    set.add(new Pattern("class0", tmp.build()));

    tmp = Vector.newBuilder();
    for (int i = SIZE; i > 0; i--) {
      tmp.add(Real.valueOf(i));
    }
    set.add(new Pattern("class1", tmp.build()));
    set.add(new Pattern("class2", Vector.of(1.0, 1.0, 1.0)));
    set.add(new Pattern("class1", Vector.of(2.0, 2.0, 2.0)));
    set.add(new Pattern("class0", Vector.of(3.0, 3.0, 3.0)));
  }
Ejemplo n.º 7
0
  /**
   * Calculates the AUC measurment.
   *
   * @param algorithm The optimisation algorithm with a NNTrainingProblem.
   * @return A Vector with the AUC for each NN output.
   */
  @Override
  public Vector getValue(Algorithm algorithm) {
    Vector solution = (Vector) algorithm.getBestSolution().getPosition();
    NNTrainingProblem problem = (NNTrainingProblem) algorithm.getOptimisationProblem();
    StandardPatternDataTable generalisationSet = problem.getGeneralisationSet();
    NeuralNetwork neuralNetwork = problem.getNeuralNetwork();
    neuralNetwork.setWeights(solution);

    // Arrange outputs and target values into ArrayLists.
    ArrayList<ArrayList<Real>> targets = new ArrayList<ArrayList<Real>>();
    ArrayList<ArrayList<Real>> outputs = new ArrayList<ArrayList<Real>>();
    // case of multiple outputs
    if (generalisationSet.getRow(0).getTarget() instanceof Vector) {
      int size = ((Vector) generalisationSet.getRow(0).getTarget()).size();
      for (int i = 0; i < size; ++i) {
        targets.add(new ArrayList<Real>());
        outputs.add(new ArrayList<Real>());
      }

      for (StandardPattern pattern : generalisationSet) {
        Vector target = (Vector) pattern.getTarget();
        Vector output = neuralNetwork.evaluatePattern(pattern);

        for (int curOutput = 0; curOutput < target.size(); ++curOutput) {
          targets.get(curOutput).add((Real) target.get(curOutput));
          outputs.get(curOutput).add((Real) output.get(curOutput));
        }
      }
    }
    // case of single output
    else {
      targets.add(new ArrayList<Real>());
      outputs.add(new ArrayList<Real>());

      for (StandardPattern pattern : generalisationSet) {
        Real target = (Real) pattern.getTarget();
        Vector output = neuralNetwork.evaluatePattern(pattern);

        targets.get(0).add(target);
        outputs.get(0).add((Real) output.get(0));
      }
    }

    // Calculate the Vector of AUC values
    Vector results = Vector.of();
    for (int curOutput = 0; curOutput < outputs.size(); ++curOutput) {
      results.add(Real.valueOf(areaUnderCurve(targets.get(curOutput), outputs.get(curOutput))));
    }

    return results;
  }
Ejemplo n.º 8
0
  @Override
  public <E extends Entity> List<E> crossover(List<E> parentCollection) {
    Preconditions.checkArgument(
        parentCollection.size() == 2, "BlendCrossoverStrategy requires 2 parents.");

    // How do we handle variable sizes? Resizing the entities?
    E offspring1 = (E) parentCollection.get(0).getClone();
    E offspring2 = (E) parentCollection.get(1).getClone();

    Vector parentChromosome1 = (Vector) parentCollection.get(0).getCandidateSolution();
    Vector parentChromosome2 = (Vector) parentCollection.get(1).getCandidateSolution();
    Vector.Builder offspringChromosome1 = Vector.newBuilder();
    Vector.Builder offspringChromosome2 = Vector.newBuilder();

    int sizeParent1 = parentChromosome1.size();
    int sizeParent2 = parentChromosome2.size();

    int minDimension = Math.min(sizeParent1, sizeParent2);

    for (int i = 0; i < minDimension; i++) {
      double gamma =
          (1 + 2 * alpha.getParameter()) * random.getRandomNumber() - alpha.getParameter();
      double value1 =
          (1 - gamma) * parentChromosome1.doubleValueOf(i)
              + gamma * parentChromosome2.doubleValueOf(i);
      double value2 =
          (1 - gamma) * parentChromosome2.doubleValueOf(i)
              + gamma * parentChromosome1.doubleValueOf(i);

      offspringChromosome1.add(Real.valueOf(value1, parentChromosome1.boundsOf(i)));
      offspringChromosome2.add(Real.valueOf(value2, parentChromosome1.boundsOf(i)));
    }

    offspring1.setCandidateSolution(offspringChromosome1.build());
    offspring2.setCandidateSolution(offspringChromosome2.build());

    return Arrays.asList(offspring1, offspring2);
  }
Ejemplo n.º 9
0
  /**
   * Puts a token into a new object of the correct CIlib type.
   *
   * @param index the index of the token in the row (its column).
   * @param token the token to be typed.
   * @return a new CIlib object of the correct type.
   */
  private Type mapTokenToType(int index, String token) {
    Type type = columnTypePrototypes.get(index);
    if (type instanceof Real) {
      return Real.valueOf(Double.parseDouble(token));
    }

    if (type instanceof StringType) {
      return new StringType(token);
    }

    // If none of the above, has to be a nominal attribute.
    HashMap<String, Integer> nominalMap = this.columnToNominalAttributesMap.get(index);
    return Int.valueOf(nominalMap.get(token));
  }
Ejemplo n.º 10
0
  @Override
  public Vector get(Particle particle) {
    Vector newPos = (Vector) delegate.get(particle);

    Particle tmp = particle.getClone();
    tmp.setPosition(newPos);
    Fitness newFitness = particle.getBehaviour().getFitnessCalculator().getFitness(tmp);

    final UniformDistribution uniform = new UniformDistribution();
    Vector newPBest =
        newPos.plus(
            Vector.newBuilder()
                .repeat(newPos.size(), Real.valueOf(1.0))
                .build()
                .multiply(
                    new P1<Number>() {
                      @Override
                      public Number _1() {
                        return uniform.getRandomNumber(
                            -granularity.getParameter(), granularity.getParameter());
                      }
                    }));
    tmp.setPosition(newPos);
    Fitness newPBestFitness = particle.getBehaviour().getFitnessCalculator().getFitness(tmp);

    if (newPBestFitness.compareTo(newFitness) < 0) {
      Vector tmpVector = Vector.copyOf(newPos);
      newPos = newPBest;
      newPBest = tmpVector;

      newPBestFitness = newFitness;
    }

    double dot =
        ((Vector) particle.getNeighbourhoodBest().getBestPosition())
            .subtract(newPos)
            .dot(newPBest.subtract(newPos));

    if (dot < 0) {
      return (Vector) particle.getPosition();
    }

    particle.put(Property.BEST_POSITION, newPBest);
    particle.put(Property.BEST_FITNESS, newPBestFitness);

    return newPos;
  }
Ejemplo n.º 11
0
  /** {@inheritDoc} */
  public Real getValue(Algorithm algorithm) {
    PSO pso = (PSO) algorithm;

    int numberParticles = pso.getTopology().size();

    Iterator<Particle> k = pso.getTopology().iterator();
    Particle particle = k.next();
    Vector averageParticlePosition = (Vector) particle.getPosition().getClone();
    while (k.hasNext()) {
      particle = k.next();
      Vector v = (Vector) particle.getPosition();
      for (int j = 0; j < averageParticlePosition.size(); ++j) {
        averageParticlePosition.setReal(
            j, averageParticlePosition.doubleValueOf(j) + v.doubleValueOf(j));
      }
    }
    for (int j = 0; j < averageParticlePosition.size(); ++j) {
      averageParticlePosition.setReal(
          j, averageParticlePosition.doubleValueOf(j) / numberParticles);
    }

    Iterator<Particle> i = pso.getTopology().iterator();
    double particleSum = 0.0;
    while (i.hasNext()) {
      particle = i.next();

      double dimensionSum = 0.0;
      Vector v = (Vector) particle.getPosition();
      for (int j = 0; j < particle.getDimension(); ++j) {
        dimensionSum +=
            (v.doubleValueOf(j) - averageParticlePosition.doubleValueOf(j))
                * (v.doubleValueOf(j) - averageParticlePosition.doubleValueOf(j));
      }
      particleSum += Math.sqrt(dimensionSum);
    }

    double diversity = particleSum / numberParticles;

    DiameterVisitor diameterVisitor = new DiameterVisitor();
    pso.accept(diameterVisitor);
    double diameter = diameterVisitor.getResult();

    return Real.valueOf(diversity / diameter);
  }
Ejemplo n.º 12
0
  @Test(expected = IllegalArgumentException.class)
  public void testVectorDistance() {
    DistanceMeasure distanceMeasure = new CosineDistanceMeasure();

    Vector v1 = new Vector();
    Vector v2 = new Vector();

    v1.add(Real.valueOf(4.0));
    v1.add(Real.valueOf(3.0));
    v1.add(Real.valueOf(2.0));

    v2.add(Real.valueOf(2.0));
    v2.add(Real.valueOf(3.0));
    v2.add(Real.valueOf(4.0));

    double distance = distanceMeasure.distance(v1, v2);
    assertTrue(distance >= -1 && distance <= 1);
    assertEquals(1 - (25.0 / 29.0), distance, 0.000000000000001);

    v1.add(Real.valueOf(22.0));

    distanceMeasure.distance(v1, v2);
  }
  @Test
  public void algorithmExecution() {
    NNDataTrainingProblem problem = new NNDataTrainingProblem();
    problem.getDataTableBuilder().setDataReader(new ARFFFileReader());
    problem.getDataTableBuilder().setSourceURL("library/src/test/resources/datasets/iris.arff");
    problem.setTrainingSetPercentage(0.7);
    problem.setGeneralizationSetPercentage(0.3);

    problem
        .getNeuralNetwork()
        .getArchitecture()
        .setArchitectureBuilder(new CascadeArchitectureBuilder());
    problem.getNeuralNetwork().setOperationVisitor(new CascadeVisitor());
    problem
        .getNeuralNetwork()
        .getArchitecture()
        .getArchitectureBuilder()
        .addLayer(new LayerConfiguration(4));
    problem
        .getNeuralNetwork()
        .getArchitecture()
        .getArchitectureBuilder()
        .addLayer(new LayerConfiguration(0));
    problem
        .getNeuralNetwork()
        .getArchitecture()
        .getArchitectureBuilder()
        .addLayer(new LayerConfiguration(1));
    problem
        .getNeuralNetwork()
        .getArchitecture()
        .getArchitectureBuilder()
        .getLayerBuilder()
        .setDomain("R(-3:3)");
    problem.initialise();

    PSO pso = new PSO();
    pso.getInitialisationStrategy().setEntityType(new DynamicParticle());
    pso.addStoppingCondition(new MeasuredStoppingCondition());
    pso.setOptimisationProblem(problem);
    pso.performInitialisation();

    CascadeNetworkExpansionReactionStrategy reaction =
        new CascadeNetworkExpansionReactionStrategy();

    Assert.assertEquals(5, ((Vector) pso.getBestSolution().getPosition()).size());
    Assert.assertEquals(5, problem.getNeuralNetwork().getWeights().size());

    for (int i = 0; i < Topologies.getBestEntity(pso.getTopology()).getDimension(); ++i) {
      ((Vector) Topologies.getBestEntity(pso.getTopology()).getPosition())
          .set(i, Real.valueOf(0.0));
      ((Vector) Topologies.getBestEntity(pso.getTopology()).getVelocity())
          .set(i, Real.valueOf(0.0));
      ((Vector) Topologies.getBestEntity(pso.getTopology()).getBestPosition())
          .set(i, Real.valueOf(0.0));
    }
    reaction.performReaction(pso);
    Assert.assertEquals(11, ((Vector) pso.getBestSolution().getPosition()).size());
    Assert.assertEquals(11, problem.getNeuralNetwork().getWeights().size());
    Assert.assertEquals(
        Vector.of(
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN),
        (Vector) Topologies.getBestEntity(pso.getTopology()).getPosition());
    Assert.assertEquals(
        Vector.of(
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN),
        (Vector) Topologies.getBestEntity(pso.getTopology()).getVelocity());
    Assert.assertEquals(
        Vector.of(
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN),
        (Vector) Topologies.getBestEntity(pso.getTopology()).getBestPosition());

    for (int i = 0; i < Topologies.getBestEntity(pso.getTopology()).getDimension(); ++i) {
      ((Vector) Topologies.getBestEntity(pso.getTopology()).getPosition())
          .set(i, Real.valueOf(0.0));
      ((Vector) Topologies.getBestEntity(pso.getTopology()).getVelocity())
          .set(i, Real.valueOf(0.0));
      ((Vector) Topologies.getBestEntity(pso.getTopology()).getBestPosition())
          .set(i, Real.valueOf(0.0));
    }
    reaction.performReaction(pso);
    Assert.assertEquals(18, ((Vector) pso.getBestSolution().getPosition()).size());
    Assert.assertEquals(18, problem.getNeuralNetwork().getWeights().size());
    Assert.assertEquals(
        Vector.of(
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN),
        (Vector) Topologies.getBestEntity(pso.getTopology()).getPosition());
    Assert.assertEquals(
        Vector.of(
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN),
        (Vector) Topologies.getBestEntity(pso.getTopology()).getVelocity());
    Assert.assertEquals(
        Vector.of(
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN),
        (Vector) Topologies.getBestEntity(pso.getTopology()).getBestPosition());

    for (int i = 0; i < Topologies.getBestEntity(pso.getTopology()).getDimension(); ++i) {
      ((Vector) Topologies.getBestEntity(pso.getTopology()).getPosition())
          .set(i, Real.valueOf(0.0));
      ((Vector) Topologies.getBestEntity(pso.getTopology()).getVelocity())
          .set(i, Real.valueOf(0.0));
      ((Vector) Topologies.getBestEntity(pso.getTopology()).getBestPosition())
          .set(i, Real.valueOf(0.0));
    }
    reaction.performReaction(pso);
    Assert.assertEquals(26, ((Vector) pso.getBestSolution().getPosition()).size());
    Assert.assertEquals(26, problem.getNeuralNetwork().getWeights().size());
    Assert.assertEquals(
        Vector.of(
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN),
        (Vector) Topologies.getBestEntity(pso.getTopology()).getPosition());
    Assert.assertEquals(
        Vector.of(
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN),
        (Vector) Topologies.getBestEntity(pso.getTopology()).getVelocity());
    Assert.assertEquals(
        Vector.of(
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            Double.NaN,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            Double.NaN),
        (Vector) Topologies.getBestEntity(pso.getTopology()).getBestPosition());
  }
  private void updateInertia(PSO pso) {

    int dimension = pso.getTopology().last().getDimension();

    if (inertiaWeight.size() < dimension) {
      Vector.Builder builder = Vector.newBuilder();
      builder.repeat(dimension, Real.valueOf(initialInertiaWeight.getParameter()));
      inertiaWeight = builder.build();
    }
    Vector.Builder builder = Vector.newBuilder();
    for (int i = 0; i < dimension; i++) {
      builder.add(
          Math.sqrt(
              Math.pow(absoluteAverageVelocityVector.doubleValueOf(i), 2)
                  + Math.pow(averageSpeedVector.doubleValueOf(i), 2)));
    }
    Vector d = builder.build(); // get the degree of convergence vector
    double max_d = 0;
    for (Numeric component : d) {
      if (component.doubleValue() > max_d) {
        max_d = component.doubleValue();
      }
    }
    if (max_d != 0) {
      Vector.Builder builder2 = Vector.newBuilder();
      for (Numeric component : d) {
        builder2.add(max_d / (max_d + component.doubleValue()));
      }
      Vector w = builder2.build();

      /*double sum_w = 0;
      for(Numeric component : w) {
          sum_w += component.doubleValue();
      }

      /*
      Vector.Builder builder3 = Vector.newBuilder();
      for(Numeric component : w) {
          builder3.add(Math.pow(dimension * component.doubleValue() / sum_w, pwr.getParameter()));
      } */

      /*
      for(Numeric component : w) {
          //builder3.add(component.doubleValue() - w_mean / w_stdDiv);
          builder3.add(component.doubleValue() * initialInertiaWeight.getParameter());
      }
      for(int i = 0; i < inertiaWeight.size(); i++) {
          builder3.add(w.doubleValueOf(i) * inertiaWeight.doubleValueOf(i));
      }
      */
      /*
      Vector m = builder3.build();
      double sum_m = 0;
      for (Numeric num : m) {
          sum_m += num.doubleValue();
      }

      double m_mean = sum_m / (double) dimension;
      double sum_diff_squared = 0;
      for(Numeric component : m) {
          sum_diff_squared += Math.pow(component.doubleValue() - m_mean, 2);
      }
      double m_stdDiv = Math.sqrt(sum_diff_squared / (double) dimension);
      */
      // System.out.println("VEL: StdDiv of M: " + m_stdDiv + ", mean of M: " + m_mean);

      for (int i = 0; i < inertiaWeight.size(); i++) {
        inertiaWeight.setReal(
            i,
            (1 - filter.getParameter()) * w.doubleValueOf(i)
                + filter.getParameter()
                    * inertiaWeight.doubleValueOf(i)); // w.doubleValueOf(i));//;
      }
    }
  }
Ejemplo n.º 15
0
  /**
   * Calculates the AUC of one output.
   *
   * @param targets The expected outputs. Each value is discetised to the closest bound.
   * @param outputs The outputs of the NN.
   * @return The AUC in the range [0,1].
   */
  public double areaUnderCurve(ArrayList<Real> targets, ArrayList<Real> outputs) {

    double negatives = 0.0;
    double positives = 0.0;

    double centerBound = (upperBound + lowerBound) / 2.0;

    // determine total positives and negatives
    for (Real curTarget : targets) {
      if (curTarget.doubleValue() > centerBound) positives += 1;
      else negatives += 1;
    }

    // plot ROC curve coordinates
    double threshold = lowerBound;
    ArrayList<Real> tpCoords = new ArrayList<Real>();
    ArrayList<Real> fpCoords = new ArrayList<Real>();

    // when all outputs are seen as true
    tpCoords.add(Real.valueOf(1.0));
    fpCoords.add(Real.valueOf(1.0));

    double newThresholdL;
    double newThresholdU;
    do {

      // calculate next threshold
      newThresholdL = upperBound;
      newThresholdU = upperBound;
      for (Real curOutput : outputs) {
        if (curOutput.doubleValue() >= threshold && curOutput.doubleValue() < newThresholdL) {
          newThresholdL = curOutput.doubleValue();
        }
      }
      for (Real curOutput : outputs) {
        if (curOutput.doubleValue() > newThresholdL && curOutput.doubleValue() < newThresholdU) {
          newThresholdU = curOutput.doubleValue();
        }
      }
      threshold = (newThresholdL + newThresholdU) / 2.0;

      // calculate tp and fp for this threshold
      double tPositive = 0;
      double fPositive = 0;
      for (int curOutput = 0; curOutput < outputs.size(); ++curOutput) {
        if (targets.get(curOutput).doubleValue() > centerBound
            && outputs.get(curOutput).doubleValue() > threshold) {
          tPositive += 1;
        } else if (targets.get(curOutput).doubleValue() <= centerBound
            && outputs.get(curOutput).doubleValue() > threshold) {
          fPositive += 1;
        }
      }
      tpCoords.add(Real.valueOf(tPositive / positives));
      fpCoords.add(Real.valueOf(fPositive / negatives));

    } while (newThresholdU < upperBound);

    // when all outputs are seen as false
    tpCoords.add(Real.valueOf(0.0));
    fpCoords.add(Real.valueOf(0.0));

    // calculate area
    double area = 0.0;
    for (int curCoord = 1; curCoord < fpCoords.size(); ++curCoord) {
      area +=
          ((tpCoords.get(curCoord - 1).doubleValue() + tpCoords.get(curCoord).doubleValue()) / 2)
              * (fpCoords.get(curCoord - 1).doubleValue()
                  - fpCoords.get(curCoord).doubleValue()); // fpCoords sorted in decending order
    }

    return area;
  }