/**
   * Convert to an array. This is used with some training algorithms that require that the "memory"
   * of the neuron(the weight and bias values) be expressed as a linear array.
   *
   * @param network The network to encode.
   * @return The memory of the neuron.
   */
  public static double[] networkToArray(final BasicNetwork network) {
    final int size = network.getStructure().calculateSize();

    // allocate an array to hold
    final double[] result = new double[size];

    int index = 0;

    for (final Layer layer : network.getStructure().getLayers()) {
      // process layer bias
      if (layer.hasBias()) {
        for (int i = 0; i < layer.getNeuronCount(); i++) {
          result[index++] = layer.getBiasWeight(i);
        }
      }

      // process synapses
      for (final Synapse synapse : network.getStructure().getPreviousSynapses(layer)) {
        if (synapse.getMatrix() != null) {
          // process each weight matrix
          for (int x = 0; x < synapse.getToNeuronCount(); x++) {
            for (int y = 0; y < synapse.getFromNeuronCount(); y++) {
              result[index++] = synapse.getMatrix().get(y, x);
            }
          }
        }
      }
    }

    return result;
  }
  /**
   * Construct a network analyze class. Analyze the specified network.
   *
   * @param network The network to analyze.
   */
  public AnalyzeNetwork(final BasicNetwork network) {
    final int assignDisabled = 0;
    final int assignedTotal = 0;
    final List<Double> biasList = new ArrayList<Double>();
    final List<Double> weightList = new ArrayList<Double>();
    final List<Double> allList = new ArrayList<Double>();

    for (int layerNumber = 0; layerNumber < network.getLayerCount() - 1; layerNumber++) {
      final int fromCount = network.getLayerNeuronCount(layerNumber);
      final int fromBiasCount = network.getLayerTotalNeuronCount(layerNumber);
      final int toCount = network.getLayerNeuronCount(layerNumber + 1);

      // weights
      for (int fromNeuron = 0; fromNeuron < fromCount; fromNeuron++) {
        for (int toNeuron = 0; toNeuron < toCount; toNeuron++) {
          final double v = network.getWeight(layerNumber, fromNeuron, toNeuron);
          weightList.add(v);
          allList.add(v);
        }
      }

      // bias
      if (fromCount != fromBiasCount) {
        final int biasNeuron = fromCount;
        for (int toNeuron = 0; toNeuron < toCount; toNeuron++) {
          final double v = network.getWeight(layerNumber, biasNeuron, toNeuron);
          biasList.add(v);
          allList.add(v);
        }
      }
    }

    for (final Layer layer : network.getStructure().getLayers()) {
      if (layer.hasBias()) {
        for (int i = 0; i < layer.getNeuronCount(); i++) {}
      }
    }

    this.disabledConnections = assignDisabled;
    this.totalConnections = assignedTotal;
    this.weights = new NumericRange(weightList);
    this.bias = new NumericRange(biasList);
    this.weightsAndBias = new NumericRange(allList);
    this.weightValues = EngineArray.listToDouble(weightList);
    this.allValues = EngineArray.listToDouble(allList);
    this.biasValues = EngineArray.listToDouble(biasList);
  }
  /**
   * Use an array to populate the memory of the neural network.
   *
   * @param array An array of doubles.
   * @param network The network to encode.
   */
  public static void arrayToNetwork(final double[] array, final BasicNetwork network) {

    int index = 0;

    for (final Layer layer : network.getStructure().getLayers()) {
      if (layer.hasBias()) {
        // process layer bias
        for (int i = 0; i < layer.getNeuronCount(); i++) {
          layer.setBiasWeight(i, array[index++]);
        }
      }

      if (network.getStructure().isConnectionLimited()) {
        index = NetworkCODEC.processSynapseLimited(network, layer, array, index);
      } else {
        index = NetworkCODEC.processSynapseFull(network, layer, array, index);
      }
    }
  }