/// <summary>
        /// The dynamic table generation.
        /// </summary>
        /// <param name="first">The first sequence.</param>
        /// <param name="second">The second sequence.</param>
        /// <returns>The dynamic table.</returns>
        private ProfileTableItem GenerateDynamicTable(Profile first, Profile second)
        {
            var length1 = first.Count + 1;
            var length2 = second.Count + 1;
            var dynamicTable = new ProfileTableItem(first, second)
                {
                    { new Index(0, 0), new DynamicTableItem(0, new List<Index>()) }
                };

            // first row set
            for (var i = 1; i < length2; i++)
            {
                var ii = i - 1; // in sequence
                dynamicTable.Add(new Index(0, i), new DynamicTableItem(i * this.Estimator.ProfileItemNucleotideDistance(second[ii], Nucleotide._), new List<Index> { new Index(0, i - 1) }));
            }

            // first column set
            for (var i = 1; i < length1; i++)
            {
                var ii = i - 1; // in sequence
                dynamicTable.Add(new Index(i, 0), new DynamicTableItem(i * this.Estimator.ProfileItemNucleotideDistance(first[ii], Nucleotide._), new List<Index> { new Index(i - 1, 0) }));
            }

            for (var i = 1; i < length1; i++)
            {
                for (var j = 1; j < length2; j++)
                {
                    var pj = new Index(i - 1, j); // same column
                    var pi = new Index(i, j - 1); // same row
                    var pij = new Index(i - 1, j - 1);
                    var ii = i - 1; // in sequence
                    var jj = j - 1; // in sequence
                    var estimates = new Dictionary<Index, double>
                        {
                            { pj, dynamicTable[pj].Distance + this.Estimator.ProfileItemNucleotideDistance(first[ii], Nucleotide._) },
                            { pi, dynamicTable[pi].Distance + this.Estimator.ProfileItemNucleotideDistance(Nucleotide._, second[jj]) },
                            {
                                pij,
                                dynamicTable[pij].Distance + this.Estimator.ProfileItemsDistance(first[ii], second[jj])
                            }
                        };

                    var d = estimates.Values.Min();
                    var dynamicTableItem = new DynamicTableItem(d, estimates.Where(e => e.Value.IsEqualTo(d)).Select(e => e.Key).ToList());
                    dynamicTable.Add(new Index(i, j), dynamicTableItem);
                }
            }

            return dynamicTable;
        }
        /// <summary>
        /// The generate aligned.
        /// </summary>
        /// <param name="alignment">The alignment.</param>
        /// <param name="table">The dynamic table.</param>
        /// <param name="way">The way in dynamic table</param>
        /// <returns>The aligned sequence variants.</returns>
        public MultipleSequence GenerateAlignedSequence(MultipleAlignment alignment, ProfileTableItem table, List<Index> way)
        {
            var sequence = new MultipleSequence();
            for (var i = 1; i < way.Count; i++)
            {
                var pred = way[i - 1];
                var cur = way[i];
                var ii = cur.Item1 - 1; // in sequence
                var jj = cur.Item2 - 1; // in sequence
                if (pred.Item1.Equals(cur.Item1))
                {
                    var secondSequence = alignment.Second.AlignedSequences[table.Second.Id];
                    sequence.Add(new Column(Column.GetClearColumn(alignment.First.Count), secondSequence[jj]));
                }
                else if (pred.Item2.Equals(cur.Item2))
                {
                    var firstSequence = alignment.First.AlignedSequences[table.First.Id];
                    sequence.Add(new Column(firstSequence[ii], Column.GetClearColumn(alignment.Second.Count)));
                }
                else
                {
                    var firstSequence = alignment.First.AlignedSequences[table.First.Id];
                    var secondSequence = alignment.Second.AlignedSequences[table.Second.Id];
                    sequence.Add(new Column(firstSequence[ii], secondSequence[jj]));
                }
            }

            return sequence;
        }
        /// <summary>
        /// The generate aligned.
        /// </summary>
        /// <param name="dynamicTable">The dynamic table.</param>
        /// <returns>The aligned sequence variants.</returns>
        public List<List<Index>> GenerateGraphWays(ProfileTableItem dynamicTable)
        {
            // fill variants
            var ways = new List<List<Index>>();
            ways.Add(new List<Index> { new Index(dynamicTable.First.Count, dynamicTable.Second.Count) });
            while (ways.Any(l => !(l.First().Item1 == 0 && l.First().Item2 == 0)))
            {
                var waysCopy = new List<List<Index>>();
                foreach (var way in ways.Where(l => !(l.First().Item1 == 0 && l.First().Item2 == 0)))
                {
                    var pair = way.First();
                    var predecessors = dynamicTable[pair].Predecessors;
                    var newWays = new List<List<Index>> { way };
                    for (var i = 1; i < predecessors.Count; i++)
                    {
                        newWays.Add(new List<Index>(way));
                    }

                    for (var i = 0; i < predecessors.Count; i++)
                    {
                        newWays[i].Insert(0, predecessors[i]);
                    }

                    waysCopy.AddRange(newWays);
                }

                ways = waysCopy;
            }

            return ways;
        }