@Test
  public void testXorEvolveOnce() throws CloneNotSupportedException {
    final TreeMap<Double, SignalProcessingWavelet> population =
        new TreeMap<Double, SignalProcessingWavelet>();

    // initialize the population
    final GlobalSignalConcentration xAxis = new GlobalSignalConcentration();
    final GlobalSignalConcentration yAxis = new GlobalSignalConcentration();
    final GlobalSignalConcentration output = new GlobalSignalConcentration();
    while (population.size() < POPULATION_SIZE) {
      SignalProcessingWavelet processor = new SignalProcessingWavelet(xAxis, output);
      processor = mutateXor(processor, xAxis, yAxis);

      processor.preTick();
      processor.tick();
      final double initialFitness =
          checkXorFitness(processor.getWavelet(), processor.getWaveCount());

      population.put(initialFitness, processor);
    }

    // run through several generations
    for (int generationIndex = 0; generationIndex < GENERATIONS; generationIndex++) {
      // check if we reached the goal prematurely.
      if (population.lastKey() >= 4.0) break;

      // fill off all but the top EXTINCTION_SIZE performing members
      while (population.size() > EXTINCTION_SIZE) population.pollFirstEntry();

      // repopulate to POPULATION_SIZE members
      ArrayList<SignalProcessingWavelet> populationArray =
          new ArrayList<SignalProcessingWavelet>(population.values());
      while (population.size() < POPULATION_SIZE) {
        SignalProcessingWavelet processor =
            populationArray.get(RANDOM.nextInt(populationArray.size()));
        processor = mutateXor(processor, xAxis, yAxis);

        processor.preTick();
        processor.tick();
        final double initialFitness =
            checkXorFitness(processor.getWavelet(), processor.getWaveCount());

        population.put(initialFitness, processor);
      }
    }

    final double bestFitness = population.lastKey();
    Assert.assertTrue(
        "did not successfully match XOR truth table: fitness: " + bestFitness, bestFitness >= 4.0);
  }
  @Test
  public void testMutationOnce() throws CloneNotSupportedException {
    GlobalSignalConcentration xAxis = new GlobalSignalConcentration();
    GlobalSignalConcentration yAxis = new GlobalSignalConcentration();
    GlobalSignalConcentration output = new GlobalSignalConcentration();
    SignalProcessingWavelet processor = new SignalProcessingWavelet(xAxis, output);
    for (int index = 0; index < 500; index++) {
      processor = processor.mutate(1.0, xAxis);
      processor = processor.mutate(1.0, yAxis);
      processor = processor.mutate(1.0);
    }

    processor.preTick();
    processor.tick();
  }
  private static SignalProcessingWavelet mutateXor(
      SignalProcessingWavelet processor,
      GlobalSignalConcentration xAxis,
      GlobalSignalConcentration yAxis)
      throws CloneNotSupportedException {
    // mutate until there are atleast 2 input signals and 1 output signal, 3 total
    // there will always be exactly 1 output signal
    SignalProcessingWavelet mutatedProcessor = processor;
    do {
      for (int mutationIndex = 0; mutationIndex < XOR_MUTATION_COUNT; mutationIndex++) {
        mutatedProcessor = mutatedProcessor.mutate(XOR_MUTABILITY, xAxis);
        mutatedProcessor = mutatedProcessor.mutate(XOR_MUTABILITY, yAxis);
        mutatedProcessor = mutatedProcessor.mutate(XOR_MUTABILITY);
      }
    } while (mutatedProcessor.getSignals().size() < 3);

    return mutatedProcessor;
  }