public void checkConstraints(ExampleTable et) {

    super.checkConstraints(et);

    RelationalAttribute relA = null;
    for (int i = 0; i < et.getNumberOfAttributes(); i++)
      if (et.getAttribute(i).getTableIndex() == this.getAttributeIndexes()[0]) {
        relA = (RelationalAttribute) et.getAttribute(i);
        break;
      }

    // sparse matrix inner relational attributes
    if (relA.getInnerAttributeCount() != 2)
      throw new IllegalArgumentException(
          "sparse matrix attribute "
              + this.getName()
              + " must wrap relational attribute with exactly two inner attributes");
    else if (!Ontology.ATTRIBUTE_VALUE_TYPE.isA(
        relA.getInnerAttributeAt(0).getValueType(), Ontology.NUMERICAL))
      throw new IllegalArgumentException(
          "sparse matrix attribute "
              + this.getName()
              + " must wrap relational attribute which inner first attribute serves as key and therefore must be numerical");
  }
  /**
   * Generates all new attributes and updates the ExampleTable. Returns a list of Attributes for the
   * newly generated attributes.
   *
   * @param exampleTable the source example table
   * @param generatorList List of FeatureGenerators
   * @return A list of Attributes
   */
  public static List<Attribute> generateAll(
      ExampleTable exampleTable, Collection<FeatureGenerator> generatorList)
      throws GenerationException {
    // LogService.getGlobal().log("Starting feature generation with " + generatorList.size() + "
    // generators.", LogService.STATUS);
    LogService.getRoot()
        .log(
            Level.FINE,
            "com.rapidminer.generator.FeatureGenerator.starting_feature_generation",
            generatorList.size());

    Iterator<FeatureGenerator> gi = generatorList.iterator();
    while (gi.hasNext()) gi.next().setExampleTable(exampleTable);

    // for performance reasons convert the list to an array
    FeatureGenerator[] generators = new FeatureGenerator[generatorList.size()];
    generatorList.toArray(generators);

    List<Attribute> newAttributeList = newAttributes(generators, exampleTable);
    // add the attributes to the example table and ensure length of the
    // DataRows
    exampleTable.addAttributes(newAttributeList);
    // LogService.getGlobal().log("Generator list: " + generatorList, LogService.STATUS);
    LogService.getRoot()
        .log(Level.FINE, "com.rapidminer.generator.FeatureGenerator.generator_list", generatorList);
    // LogService.getGlobal().log("Input set has " + exampleTable.getAttributeCount() + " features,
    // " + exampleTable.size() + " examples.", LogService.STATUS);
    LogService.getRoot()
        .log(
            Level.FINE,
            "com.rapidminer.generator.FeatureGenerator.input_has_feature_count_and_example_count",
            new Object[] {exampleTable.getAttributeCount(), exampleTable.size()});

    // generate the attribute values:
    DataRowReader reader = exampleTable.getDataRowReader();
    while (reader.hasNext()) {
      DataRow dataRow = reader.next();

      for (int j = 0; j < generators.length; j++) {
        generators[j].generate(dataRow);
      }
    }

    // LogService.getGlobal().log("Finished feature generation.", LogService.STATUS);
    LogService.getRoot()
        .log(Level.FINE, "com.rapidminer.generator.FeatureGenerator.finished_feature_generation");
    // LogService.getGlobal().log("Generated set has " + exampleTable.getAttributeCount() + "
    // features, " + exampleTable.size() + " examples.", LogService.STATUS);
    LogService.getRoot()
        .log(
            Level.FINE,
            "com.rapidminer.generator.FeatureGenerator.generated_set_has_feature_count_and_example_count",
            new Object[] {exampleTable.getAttributeCount(), exampleTable.size()});

    return newAttributeList;
  }