private Alphabet(int codeLength, int alphabetSize, String[] letters, Map<String, Byte> letterIndices, Map<Byte, Byte> reverseComplements) {
    if (Math.pow(alphabetSize, codeLength) != letters.length) {
      throw new IllegalArgumentException("letters array size should be equal to alphabetSize ** codeLength");
    }
    if (letterIndices.size() != letters.length || letterIndices.size() != reverseComplements.size()) {
      throw new IllegalArgumentException("letters and complements sizes are not compatible");
    }
    for (String k: letterIndices.keySet()) {
      if (k.length() != codeLength) {
        throw new IllegalArgumentException("Key size should be equal to code size");
      }
      if (k != letters[letterIndices.get(k)]) {
        throw new IllegalArgumentException("Letters should be compatible with letter indices");
      }
    }
    for (Map.Entry<Byte,Byte> entry: reverseComplements.entrySet()) {
      if (entry.getKey() != reverseComplements.get(entry.getValue())) {
        throw new IllegalArgumentException("Reverse of reverse should be equal to itself");
      }
    }
    this.codeLength = codeLength;
    this.alphabetSize = alphabetSize;
    this.letters = letters;
    this.letterIndices = letterIndices;
    this.reverseComplements = reverseComplements;
  }