public DiscreteDataRetriever(List<Chord> chordsInOrder, int clusterSize = 2, int windowSize = 20)
        {
            chordsInOrder.NullCheck();
            chordsInOrder.Any().AssertTrue();

            this.Chords = chordsInOrder.AsReadOnly();

            this.WindowSize = windowSize;
            this.NGramSize = clusterSize;

            this.HomogenousWindowingData = HomogenousNGrams<Chord>.BuildNGrams(this.NGramSize, this.Chords.ToList());

            this.badOkayGoodChords = Tuple.Create<List<NGram<Chord>[]>, List<NGram<Chord>[]>, List<NGram<Chord>[]>>(this.RetrieveBad(), this.RetrieveOkay(), this.RetrieveGood());
        }
        public DiscreteNeuralNetworkByChord(List<NGram<Chord>[]> bad, List<NGram<Chord>[]> okay, List<NGram<Chord>[]> good, IActivationFunction function)
        {
            bad.NullCheck();
            okay.NullCheck();
            good.NullCheck();

            bad.Any().AssertTrue();
            okay.Any().AssertTrue();
            good.Any().AssertTrue();

            List<Tuple<double[], double[]>> input = new List<Tuple<double[], double[]>>(bad.Count + okay.Count + good.Count);

            input.AddRange(
                bad.Select(x => new Tuple<double[], double[]>(
                    x.SelectMany(y => y.SelectMany(p => ConvertChordIntoTrainingInput(p))).ToArray(),
                    Enumerable.Repeat<double>(DiscreteNeuralNetworkByChord.BADWEIGHT, bad.Count).ToArray())));

            input.AddRange(
                okay.Select(x => new Tuple<double[], double[]>(
                    x.SelectMany(y => y.SelectMany(p => ConvertChordIntoTrainingInput(p))).ToArray(),
                    Enumerable.Repeat<double>(OkayWeight, okay.Count).ToArray())));

            input.AddRange(
                good.Select(x => new Tuple<double[], double[]>(
                    x.SelectMany(y => y.SelectMany(p => ConvertChordIntoTrainingInput(p))).ToArray(),
                    Enumerable.Repeat<double>(DiscreteNeuralNetworkByChord.GOODWEIGHT, good.Count).ToArray())));

            this.Max = input.Max(x => x.Item1.Max());
            int minIndex = input.Min(x => x.Item1.Length);

            var normalized = input.Select(item => Tuple.Create(item.Item1.Take(minIndex).Select(x => x / this.Max).ToArray(), item.Item2.Take(minIndex).ToArray())).ToArray();

            this.trainingData = normalized.ToArray();

            this.ActivationNetwork = new ActivationNetwork(function, this.trainingData.Max(y => y.Item1.Length), (HiddenLayerSize == 0) ? 23 : HiddenLayerSize, 1);
            this.LearningMethod = new ResilientBackpropagationLearning(this.ActivationNetwork);
            this.ActivationNetwork.Randomize();
        }
        public LilyPondBuilder(List<Chord> a)
        {
            a.NullCheck();

            this.innerChords = a;
        }