1 | #include "muscle.h" |
---|
2 | #include "diaglist.h" |
---|
3 | #include "pwpath.h" |
---|
4 | |
---|
5 | #define MAX(x, y) ((x) > (y) ? (x) : (y)) |
---|
6 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) |
---|
7 | |
---|
8 | void DiagList::Add(const Diag &d) |
---|
9 | { |
---|
10 | if (m_uCount == MAX_DIAGS) |
---|
11 | Quit("DiagList::Add, overflow %u", m_uCount); |
---|
12 | m_Diags[m_uCount] = d; |
---|
13 | ++m_uCount; |
---|
14 | } |
---|
15 | |
---|
16 | void DiagList::Add(unsigned uStartPosA, unsigned uStartPosB, unsigned uLength) |
---|
17 | { |
---|
18 | Diag d; |
---|
19 | d.m_uStartPosA = uStartPosA; |
---|
20 | d.m_uStartPosB = uStartPosB; |
---|
21 | d.m_uLength = uLength; |
---|
22 | Add(d); |
---|
23 | } |
---|
24 | |
---|
25 | const Diag &DiagList::Get(unsigned uIndex) const |
---|
26 | { |
---|
27 | if (uIndex >= m_uCount) |
---|
28 | Quit("DiagList::Get(%u), count=%u", uIndex, m_uCount); |
---|
29 | return m_Diags[uIndex]; |
---|
30 | } |
---|
31 | |
---|
32 | void DiagList::LogMe() const |
---|
33 | { |
---|
34 | Log("DiagList::LogMe, count=%u\n", m_uCount); |
---|
35 | Log(" n StartA StartB Length\n"); |
---|
36 | Log("--- ------ ------ ------\n"); |
---|
37 | for (unsigned n = 0; n < m_uCount; ++n) |
---|
38 | { |
---|
39 | const Diag &d = m_Diags[n]; |
---|
40 | Log("%3u %6u %6u %6u\n", |
---|
41 | n, d.m_uStartPosA, d.m_uStartPosB, d.m_uLength); |
---|
42 | } |
---|
43 | } |
---|
44 | |
---|
45 | void DiagList::FromPath(const PWPath &Path) |
---|
46 | { |
---|
47 | Clear(); |
---|
48 | |
---|
49 | const unsigned uEdgeCount = Path.GetEdgeCount(); |
---|
50 | unsigned uLength = 0; |
---|
51 | unsigned uStartPosA; |
---|
52 | unsigned uStartPosB; |
---|
53 | for (unsigned uEdgeIndex = 0; uEdgeIndex < uEdgeCount; ++uEdgeIndex) |
---|
54 | { |
---|
55 | const PWEdge &Edge = Path.GetEdge(uEdgeIndex); |
---|
56 | |
---|
57 | // Typical cases |
---|
58 | if (Edge.cType == 'M') |
---|
59 | { |
---|
60 | if (0 == uLength) |
---|
61 | { |
---|
62 | uStartPosA = Edge.uPrefixLengthA - 1; |
---|
63 | uStartPosB = Edge.uPrefixLengthB - 1; |
---|
64 | } |
---|
65 | ++uLength; |
---|
66 | } |
---|
67 | else |
---|
68 | { |
---|
69 | if (uLength >= g_uMinDiagLength) |
---|
70 | Add(uStartPosA, uStartPosB, uLength); |
---|
71 | uLength = 0; |
---|
72 | } |
---|
73 | } |
---|
74 | |
---|
75 | // Special case for last edge |
---|
76 | if (uLength >= g_uMinDiagLength) |
---|
77 | Add(uStartPosA, uStartPosB, uLength); |
---|
78 | } |
---|
79 | |
---|
80 | bool DiagList::NonZeroIntersection(const Diag &d) const |
---|
81 | { |
---|
82 | for (unsigned n = 0; n < m_uCount; ++n) |
---|
83 | { |
---|
84 | const Diag &d2 = m_Diags[n]; |
---|
85 | if (DiagOverlap(d, d2) > 0) |
---|
86 | return true; |
---|
87 | } |
---|
88 | return false; |
---|
89 | } |
---|
90 | |
---|
91 | // DialogOverlap returns the length of the overlapping |
---|
92 | // section of the two diagonals along the diagonals |
---|
93 | // themselves; in other words, the length of |
---|
94 | // the intersection of the two sets of cells in |
---|
95 | // the matrix. |
---|
96 | unsigned DiagOverlap(const Diag &d1, const Diag &d2) |
---|
97 | { |
---|
98 | // Determine where the diagonals intersect the A |
---|
99 | // axis (extending them if required). If they |
---|
100 | // intersect at different points, they do not |
---|
101 | // overlap. Coordinates on a diagonal are |
---|
102 | // given by B = A + c where c is the value of |
---|
103 | // A at the intersection with the A axis. |
---|
104 | // Hence, c = B - A for any point on the diagonal. |
---|
105 | int c1 = (int) d1.m_uStartPosB - (int) d1.m_uStartPosA; |
---|
106 | int c2 = (int) d2.m_uStartPosB - (int) d2.m_uStartPosA; |
---|
107 | if (c1 != c2) |
---|
108 | return 0; |
---|
109 | |
---|
110 | assert(DiagOverlapA(d1, d2) == DiagOverlapB(d1, d2)); |
---|
111 | return DiagOverlapA(d1, d2); |
---|
112 | } |
---|
113 | |
---|
114 | // DialogOverlapA returns the length of the overlapping |
---|
115 | // section of the projection of the two diagonals onto |
---|
116 | // the A axis. |
---|
117 | unsigned DiagOverlapA(const Diag &d1, const Diag &d2) |
---|
118 | { |
---|
119 | unsigned uMaxStart = MAX(d1.m_uStartPosA, d2.m_uStartPosA); |
---|
120 | unsigned uMinEnd = MIN(d1.m_uStartPosA + d1.m_uLength - 1, |
---|
121 | d2.m_uStartPosA + d2.m_uLength - 1); |
---|
122 | |
---|
123 | int iLength = (int) uMinEnd - (int) uMaxStart + 1; |
---|
124 | if (iLength < 0) |
---|
125 | return 0; |
---|
126 | return (unsigned) iLength; |
---|
127 | } |
---|
128 | |
---|
129 | // DialogOverlapB returns the length of the overlapping |
---|
130 | // section of the projection of the two diagonals onto |
---|
131 | // the B axis. |
---|
132 | unsigned DiagOverlapB(const Diag &d1, const Diag &d2) |
---|
133 | { |
---|
134 | unsigned uMaxStart = MAX(d1.m_uStartPosB, d2.m_uStartPosB); |
---|
135 | unsigned uMinEnd = MIN(d1.m_uStartPosB + d1.m_uLength - 1, |
---|
136 | d2.m_uStartPosB + d2.m_uLength - 1); |
---|
137 | |
---|
138 | int iLength = (int) uMinEnd - (int) uMaxStart + 1; |
---|
139 | if (iLength < 0) |
---|
140 | return 0; |
---|
141 | return (unsigned) iLength; |
---|
142 | } |
---|
143 | |
---|
144 | // Returns true if the two diagonals can be on the |
---|
145 | // same path through the DP matrix. If DiagCompatible |
---|
146 | // returns false, they cannot be in the same path |
---|
147 | // and hence "contradict" each other. |
---|
148 | bool DiagCompatible(const Diag &d1, const Diag &d2) |
---|
149 | { |
---|
150 | if (DiagOverlap(d1, d2) > 0) |
---|
151 | return true; |
---|
152 | return 0 == DiagOverlapA(d1, d2) && 0 == DiagOverlapB(d1, d2); |
---|
153 | } |
---|
154 | |
---|
155 | // Returns the length of the "break" between two diagonals. |
---|
156 | unsigned DiagBreak(const Diag &d1, const Diag &d2) |
---|
157 | { |
---|
158 | int c1 = (int) d1.m_uStartPosB - (int) d1.m_uStartPosA; |
---|
159 | int c2 = (int) d2.m_uStartPosB - (int) d2.m_uStartPosA; |
---|
160 | if (c1 != c2) |
---|
161 | return 0; |
---|
162 | |
---|
163 | int iMaxStart = MAX(d1.m_uStartPosA, d2.m_uStartPosA); |
---|
164 | int iMinEnd = MIN(d1.m_uStartPosA + d1.m_uLength - 1, |
---|
165 | d2.m_uStartPosA + d1.m_uLength - 1); |
---|
166 | int iBreak = iMaxStart - iMinEnd - 1; |
---|
167 | if (iBreak < 0) |
---|
168 | return 0; |
---|
169 | return (unsigned) iBreak; |
---|
170 | } |
---|
171 | |
---|
172 | // Merge diagonals that are continuations of each other with |
---|
173 | // short breaks of up to length g_uMaxDiagBreak. |
---|
174 | // In a sorted list of diagonals, we only have to check |
---|
175 | // consecutive entries. |
---|
176 | void MergeDiags(DiagList &DL) |
---|
177 | { |
---|
178 | return; |
---|
179 | #if DEBUG |
---|
180 | if (!DL.IsSorted()) |
---|
181 | Quit("MergeDiags: !IsSorted"); |
---|
182 | #endif |
---|
183 | |
---|
184 | // TODO: Fix this! |
---|
185 | // Breaks must be with no offset (no gaps) |
---|
186 | const unsigned uCount = DL.GetCount(); |
---|
187 | if (uCount <= 1) |
---|
188 | return; |
---|
189 | |
---|
190 | DiagList NewList; |
---|
191 | |
---|
192 | Diag MergedDiag; |
---|
193 | const Diag *ptrPrev = &DL.Get(0); |
---|
194 | for (unsigned i = 1; i < uCount; ++i) |
---|
195 | { |
---|
196 | const Diag *ptrDiag = &DL.Get(i); |
---|
197 | unsigned uBreakLength = DiagBreak(*ptrPrev, *ptrDiag); |
---|
198 | if (uBreakLength <= g_uMaxDiagBreak) |
---|
199 | { |
---|
200 | MergedDiag.m_uStartPosA = ptrPrev->m_uStartPosA; |
---|
201 | MergedDiag.m_uStartPosB = ptrPrev->m_uStartPosB; |
---|
202 | MergedDiag.m_uLength = ptrPrev->m_uLength + ptrDiag->m_uLength |
---|
203 | + uBreakLength; |
---|
204 | ptrPrev = &MergedDiag; |
---|
205 | } |
---|
206 | else |
---|
207 | { |
---|
208 | NewList.Add(*ptrPrev); |
---|
209 | ptrPrev = ptrDiag; |
---|
210 | } |
---|
211 | } |
---|
212 | NewList.Add(*ptrPrev); |
---|
213 | DL.Copy(NewList); |
---|
214 | } |
---|
215 | |
---|
216 | void DiagList::DeleteIncompatible() |
---|
217 | { |
---|
218 | assert(IsSorted()); |
---|
219 | |
---|
220 | if (m_uCount < 2) |
---|
221 | return; |
---|
222 | |
---|
223 | bool *bFlagForDeletion = new bool[m_uCount]; |
---|
224 | for (unsigned i = 0; i < m_uCount; ++i) |
---|
225 | bFlagForDeletion[i] = false; |
---|
226 | |
---|
227 | for (unsigned i = 0; i < m_uCount; ++i) |
---|
228 | { |
---|
229 | const Diag &di = m_Diags[i]; |
---|
230 | for (unsigned j = i + 1; j < m_uCount; ++j) |
---|
231 | { |
---|
232 | const Diag &dj = m_Diags[j]; |
---|
233 | |
---|
234 | // Verify sorted correctly |
---|
235 | assert(di.m_uStartPosA <= dj.m_uStartPosA); |
---|
236 | |
---|
237 | // If two diagonals are incompatible and |
---|
238 | // one is is much longer than the other, |
---|
239 | // keep the longer one. |
---|
240 | if (!DiagCompatible(di, dj)) |
---|
241 | { |
---|
242 | if (di.m_uLength > dj.m_uLength*4) |
---|
243 | bFlagForDeletion[j] = true; |
---|
244 | else if (dj.m_uLength > di.m_uLength*4) |
---|
245 | bFlagForDeletion[i] = true; |
---|
246 | else |
---|
247 | { |
---|
248 | bFlagForDeletion[i] = true; |
---|
249 | bFlagForDeletion[j] = true; |
---|
250 | } |
---|
251 | } |
---|
252 | } |
---|
253 | } |
---|
254 | |
---|
255 | for (unsigned i = 0; i < m_uCount; ++i) |
---|
256 | { |
---|
257 | const Diag &di = m_Diags[i]; |
---|
258 | if (bFlagForDeletion[i]) |
---|
259 | continue; |
---|
260 | |
---|
261 | for (unsigned j = i + 1; j < m_uCount; ++j) |
---|
262 | { |
---|
263 | const Diag &dj = m_Diags[j]; |
---|
264 | if (bFlagForDeletion[j]) |
---|
265 | continue; |
---|
266 | |
---|
267 | // Verify sorted correctly |
---|
268 | assert(di.m_uStartPosA <= dj.m_uStartPosA); |
---|
269 | |
---|
270 | // If sort order in B different from sorted order in A, |
---|
271 | // either diags are incompatible or we detected a repeat |
---|
272 | // or permutation. |
---|
273 | if (di.m_uStartPosB >= dj.m_uStartPosB || !DiagCompatible(di, dj)) |
---|
274 | { |
---|
275 | bFlagForDeletion[i] = true; |
---|
276 | bFlagForDeletion[j] = true; |
---|
277 | } |
---|
278 | } |
---|
279 | } |
---|
280 | |
---|
281 | unsigned uNewCount = 0; |
---|
282 | Diag *NewDiags = new Diag[m_uCount]; |
---|
283 | for (unsigned i = 0; i < m_uCount; ++i) |
---|
284 | { |
---|
285 | if (bFlagForDeletion[i]) |
---|
286 | continue; |
---|
287 | |
---|
288 | const Diag &d = m_Diags[i]; |
---|
289 | NewDiags[uNewCount] = d; |
---|
290 | ++uNewCount; |
---|
291 | } |
---|
292 | memcpy(m_Diags, NewDiags, uNewCount*sizeof(Diag)); |
---|
293 | m_uCount = uNewCount; |
---|
294 | delete[] NewDiags; |
---|
295 | } |
---|
296 | |
---|
297 | void DiagList::Copy(const DiagList &DL) |
---|
298 | { |
---|
299 | Clear(); |
---|
300 | unsigned uCount = DL.GetCount(); |
---|
301 | for (unsigned i = 0; i < uCount; ++i) |
---|
302 | Add(DL.Get(i)); |
---|
303 | } |
---|
304 | |
---|
305 | // Check if sorted in increasing order of m_uStartPosA |
---|
306 | bool DiagList::IsSorted() const |
---|
307 | { |
---|
308 | return true; |
---|
309 | unsigned uCount = GetCount(); |
---|
310 | for (unsigned i = 1; i < uCount; ++i) |
---|
311 | if (m_Diags[i-1].m_uStartPosA > m_Diags[i].m_uStartPosA) |
---|
312 | return false; |
---|
313 | return true; |
---|
314 | } |
---|
315 | |
---|
316 | // Sort in increasing order of m_uStartPosA |
---|
317 | // Dumb bubble sort, but don't care about speed |
---|
318 | // because don't get long lists. |
---|
319 | void DiagList::Sort() |
---|
320 | { |
---|
321 | if (m_uCount < 2) |
---|
322 | return; |
---|
323 | |
---|
324 | bool bContinue = true; |
---|
325 | while (bContinue) |
---|
326 | { |
---|
327 | bContinue = false; |
---|
328 | for (unsigned i = 0; i < m_uCount - 1; ++i) |
---|
329 | { |
---|
330 | if (m_Diags[i].m_uStartPosA > m_Diags[i+1].m_uStartPosA) |
---|
331 | { |
---|
332 | Diag Tmp = m_Diags[i]; |
---|
333 | m_Diags[i] = m_Diags[i+1]; |
---|
334 | m_Diags[i+1] = Tmp; |
---|
335 | bContinue = true; |
---|
336 | } |
---|
337 | } |
---|
338 | } |
---|
339 | } |
---|
340 | |
---|
341 | //void TestDiag() |
---|
342 | // { |
---|
343 | // Diag d1; |
---|
344 | // Diag d2; |
---|
345 | // Diag d3; |
---|
346 | // |
---|
347 | // d1.m_uStartPosA = 0; |
---|
348 | // d1.m_uStartPosB = 1; |
---|
349 | // d1.m_uLength = 32; |
---|
350 | // |
---|
351 | // d2.m_uStartPosA = 55; |
---|
352 | // d2.m_uStartPosB = 70; |
---|
353 | // d2.m_uLength = 36; |
---|
354 | // |
---|
355 | // d3.m_uStartPosA = 102; |
---|
356 | // d3.m_uStartPosB = 122; |
---|
357 | // d3.m_uLength = 50; |
---|
358 | // |
---|
359 | // DiagList DL; |
---|
360 | // DL.Add(d1); |
---|
361 | // DL.Add(d2); |
---|
362 | // DL.Add(d3); |
---|
363 | // |
---|
364 | // Log("Before DeleteIncompatible:\n"); |
---|
365 | // DL.LogMe(); |
---|
366 | // DL.DeleteIncompatible(); |
---|
367 | // |
---|
368 | // Log("After DeleteIncompatible:\n"); |
---|
369 | // DL.LogMe(); |
---|
370 | // |
---|
371 | // MergeDiags(DL); |
---|
372 | // Log("After Merge:\n"); |
---|
373 | // DL.LogMe(); |
---|
374 | // |
---|
375 | // DPRegionList RL; |
---|
376 | // DiagListToDPRegionList(DL, RL, 200, 200); |
---|
377 | // RL.LogMe(); |
---|
378 | // } |
---|