/** {@inheritDoc } */
  public DomainRegistry generateDomain(int fanin) {

    DomainRegistry domainRegistry = provider.generateDomain(fanin);
    String domainString = domainRegistry.getDomainString();
    domainRegistry.setDomainString(
        domainString
            + ","
            + lambdaDomainPrototype.getDomainString()
            + ","
            + gammaDomainPrototype.getDomainString());

    return domainRegistry;
  }
  public AngleModulation() {
    precision = 3;
    bitsPerDimension = 0;
    domainRegistry = new StringBasedDomainRegistry();

    domainRegistry.setDomainString("R(-1.0:1.0)^4");
  }
  /**
   * @TODO: This needs to use an API for domain string manipulation
   *
   * @param domain
   * @return
   */
  public int getRequiredNumberOfBits(DomainRegistry domain) {
    if (domain.getDomainString().contains("B")) {
      return 1;
    } else {
      String range = domain.getDomainString();

      // now remove all the irrelevant details from the domain provided
      range = range.substring(range.indexOf('(') + 1);
      range = range.substring(0, range.indexOf(')'));

      String[] bounds = range.split(":");
      lowerBound = Double.valueOf(bounds[0]).doubleValue();
      upperBound = Double.valueOf(bounds[1]).doubleValue();

      double greaterRange = Math.abs(lowerBound) + Math.abs(upperBound);
      double expandedRange = greaterRange * Math.pow(10, getPrecision());

      return Double.valueOf(Math.ceil(Math.log(expandedRange) / Math.log(2.0))).intValue();
    }
  }
  /**
   * Builds a layer by cloning a prototype neuron and adding to it weights such that it is fully
   * connected to the feeding layer.
   *
   * @param layerConfiguration
   * @param previousLayerAbsoluteSize
   * @return the built layer.
   */
  @Override
  public Layer buildLayer(LayerConfiguration layerConfiguration, int previousLayerAbsoluteSize) {
    prototypeNeuron.setActivationFunction(layerConfiguration.getActivationFunction());
    int layerSize = layerConfiguration.getSize();
    boolean bias = layerConfiguration.isBias();

    // determine correct domain registry
    DomainRegistry domainRegistry = domainProvider.generateDomain(previousLayerAbsoluteSize);

    // set domain for prototype neuron
    prototypeNeuron.setDomain(domainRegistry.getDomainString());

    // get prototype weight vector
    Vector prototypeWeightVector = null;
    try {
      prototypeWeightVector = (Vector) domainRegistry.getBuiltRepresentation();
    } catch (ClassCastException exception) {
      throw new UnsupportedOperationException(
          "The domain string of the neural network weights has to be real valued");
    }

    // add neurons to layer
    Layer layer = new Layer();
    for (int i = 0; i < layerSize; i++) {
      Neuron newNeuron = prototypeNeuron.getClone();

      Vector weights = prototypeWeightVector.getClone();
      // TODO: initialisation should be done by training algorithm
      this.getWeightInitialisationStrategy().initialise(weights);
      newNeuron.setWeights(weights);
      layer.add(newNeuron);
    }
    if (bias) {
      layer.add(new BiasNeuron());
      layer.setBias(true);
    }
    return layer;
  }