Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
LCS.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 
7 namespace SiliconStudio.Quantum
8 {
9  /// <summary>
10  /// Algorithms to solve the Longest Common Subsequence problem.
11  /// http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Longest_common_subsequence
12  /// </summary>
13  // TODO: probably not useful anymore here, but could be moved to Core since it's an useful algorithm.
14  public static class LCS
15  {
16  public static int[,] GetLCS<T>(IList<T> str1, IList<T> str2, IEqualityComparer<T> comparer = null)
17  {
18  if (comparer == null) comparer = EqualityComparer<T>.Default;
19 
20  int[,] table;
21  GetLCSInternal(str1, str2, out table, comparer);
22  return table;
23  }
24 
25  public static List<T> ReadLCSFromBacktrack<T>(int[,] backtrack, IList<T> string1, IList<T> string2, IEqualityComparer<T> comparer = null)
26  {
27  if (comparer == null) comparer = EqualityComparer<T>.Default;
28 
29  var result = new List<T>();
30  ReadLCSFromBacktrack(backtrack, string1, string2, string1.Count - 1, string2.Count - 1, result, comparer);
31 
32  return result;
33  }
34 
35  public enum DiffAction
36  {
37  Add,
38  Remove,
39  Skip,
40  }
41 
42  public struct Diff
43  {
44  public DiffAction Action { get; set; }
45  public int SourceIndex { get; set; }
46  }
47 
48  public static void ApplyDiff<T>(IList<T> list1, IList<T> list2, List<Diff> differences, Func<T, T> copyItem = null)
49  {
50  int index = 0;
51  foreach (var difference in differences)
52  {
53  switch (difference.Action)
54  {
55  case DiffAction.Skip:
56  index++;
57  break;
58  case DiffAction.Add:
59  list1.Insert(index, copyItem != null ? copyItem(list2[difference.SourceIndex]) : list2[difference.SourceIndex]);
60  index++;
61  break;
62  case DiffAction.Remove:
63  list1.RemoveAt(index);
64  break;
65  }
66  }
67  }
68 
69  public static List<Diff> GenerateDiff<T>(int[,] backtrack, IList<T> list1, IList<T> list2, IEqualityComparer<T> comparer = null)
70  {
71  if (comparer == null) comparer = EqualityComparer<T>.Default;
72 
73  var differences = new List<Diff>();
74  GenerateDiff(backtrack, list1, list2, list1.Count - 1, list2.Count - 1, differences, comparer);
75 
76  return differences;
77  }
78 
79  private static void GenerateDiff<T>(int[,] backtrack, IList<T> list1, IList<T> list2, int list1Position, int list2Position, List<Diff> differences, IEqualityComparer<T> comparer)
80  {
81  if (list1Position >= 0 && list2Position >= 0 && comparer.Equals(list1[list1Position], list2[list2Position]))
82  {
83  GenerateDiff(backtrack, list1, list2, list1Position - 1, list2Position - 1, differences, comparer);
84  // No changes
85  differences.Add(new Diff { Action = DiffAction.Skip });
86  }
87  else
88  {
89  if (list2Position >= 0 && (list1Position == -1 || backtrack[list1Position + 1, list2Position] >= backtrack[list1Position, list2Position + 1]))
90  {
91  GenerateDiff(backtrack, list1, list2, list1Position, list2Position - 1, differences, comparer);
92  // Add list2[list2Position]
93  differences.Add(new Diff { Action = DiffAction.Add, SourceIndex = list2Position });
94  }
95  else if (list1Position >= 0 && (list2Position == -1 || backtrack[list1Position + 1, list2Position] < backtrack[list1Position, list2Position + 1]))
96  {
97  GenerateDiff(backtrack, list1, list2, list1Position - 1, list2Position, differences, comparer);
98  // Remove list1[list1Position]
99  differences.Add(new Diff { Action = DiffAction.Remove });
100  }
101  }
102  }
103 
104  private static void GetLCSInternal<T>(IList<T> list1, IList<T> list2, out int[,] matrix, IEqualityComparer<T> comparer)
105  {
106  matrix = null;
107 
108  if (list1.Count == 0 || list2.Count == 0)
109  {
110  return;
111  }
112 
113  var table = new int[list1.Count + 1, list2.Count + 1];
114  for (int i = 0; i < table.GetLength(0); i++)
115  {
116  table[i, 0] = 0;
117  }
118  for (int j = 0; j < table.GetLength(1); j++)
119  {
120  table[0, j] = 0;
121  }
122 
123  for (int i = 1; i < table.GetLength(0); i++)
124  {
125  for (int j = 1; j < table.GetLength(1); j++)
126  {
127  if (comparer.Equals(list1[i - 1], list2[j - 1]))
128  table[i, j] = table[i - 1, j - 1] + 1;
129  else
130  {
131  if (table[i, j - 1] > table[i - 1, j])
132  table[i, j] = table[i, j - 1];
133  else
134  table[i, j] = table[i - 1, j];
135  }
136  }
137  }
138 
139  matrix = table;
140  }
141 
142  private static void ReadLCSFromBacktrack<T>(int[,] backtrack, IList<T> list1, IList<T> list2, int list1Position, int list2Position, ICollection<T> result, IEqualityComparer<T> comparer)
143  {
144  if ((list1Position < 0) || (list2Position < 0))
145  {
146  }
147  else if (comparer.Equals(list1[list1Position], list2[list2Position]))
148  {
149  ReadLCSFromBacktrack(backtrack, list1, list2, list1Position - 1, list2Position - 1, result, comparer);
150  result.Add(list1[list1Position]);
151  }
152  else
153  {
154  if (backtrack[list1Position, list2Position - 1] >= backtrack[list1Position - 1, list2Position])
155  {
156  ReadLCSFromBacktrack(backtrack, list1, list2, list1Position, list2Position - 1, result, comparer);
157  }
158  else
159  {
160  ReadLCSFromBacktrack(backtrack, list1, list2, list1Position - 1, list2Position, result, comparer);
161  }
162  }
163  }
164  }
165 }
Algorithms to solve the Longest Common Subsequence problem. http://en.wikibooks.org/wiki/Algorithm_Im...
Definition: LCS.cs:14