public SnakeWithCharResults( Snake snake, List<CharSnake> charSnakes ) { Snake = snake; CharSnakes = charSnakes; }
//----------------------------------------------------------------------------------------- // MiddleSnake string public static SnakePair? MiddleSnake( string[] pa, int a0, int N, string[] pb, int b0, int M, V VForward, V VReverse ) { //int MAX = N + M; int MAX = ( N + M ) / 2 + 1; int DELTA = N - M; VReverse.InitStub( N, M, MAX ); bool DeltaIsEven = ( DELTA % 2 ) == 0; //Debug.WriteLine( "DELTA: " + DELTA + " which is " + ( DeltaIsEven ? "even => checking reverse" : "odd => checking forward" ) ); for ( int d = 0 ; d <= MAX ; d++ ) { // forward // checks against reverse D-1 for ( int k = -d ; k <= d ; k += 2 ) { bool down = ( k == -d || ( k != d && VForward[ k - 1 ] < VForward[ k + 1 ] ) ); int xStart = down ? VForward[ k + 1 ] : VForward[ k - 1 ]; int yStart = xStart - ( down ? k + 1 : k - 1 ); int xEnd = down ? xStart : xStart + 1; int yEnd = xEnd - k; int snake = 0; while ( xEnd < N && yEnd < M && pa[ xEnd + a0 ] == pb[ yEnd + b0 ] ) { xEnd++; yEnd++; snake++; } VForward[ k ] = xEnd; // if Δ is odd and k ϵ [ Δ - ( D - 1 ), Δ + ( D - 1 ) ] if ( DeltaIsEven || k < DELTA - ( d - 1 ) || k > DELTA + ( d - 1 ) ) continue; // if the path overlaps the furthest reaching reverse ( D - 1 )-path in diagonal k if ( VForward[ k ] < VReverse[ k ] ) continue; // overlap :) var forward = new Snake( a0, N, b0, M, true, xStart + a0, yStart + b0, down, snake ); //Debug.WriteLine( "D:" + d + " - " + forward ); return new SnakePair { D = d, Forward = forward }; } // backward // checks against forward D for ( int k = -d + DELTA ; k <= d + DELTA ; k += 2 ) { bool up = ( k == d + DELTA || ( k != -d + DELTA && VReverse[ k - 1 ] < VReverse[ k + 1 ] ) ); int xStart = up ? VReverse[ k - 1 ] : VReverse[ k + 1 ]; int yStart = xStart - ( up ? k - 1 : k + 1 ); int xEnd = up ? xStart : xStart - 1; int yEnd = xEnd - k; int snake = 0; while ( xEnd > 0 && yEnd > 0 && pa[ xEnd + a0 - 1 ] == pb[ yEnd + b0 - 1 ] ) { xEnd--; yEnd--; snake++; } VReverse[ k ] = xEnd; // remember: our k is actually k + Δ // if Δ is even and k + Δ ϵ [ -D, D ] if ( !DeltaIsEven || k < -d || k > d ) continue; // if the path overlaps the furthest reaching forward D-path in diagonal k + Δ if ( VReverse[ k ] > VForward[ k ] ) continue; // overlap :) var reverse = new Snake( a0, N, b0, M, false, xStart + a0, yStart + b0, up, snake ); //Debug.WriteLine( "D:" + d + " - " + reverse ); if ( d == 1 && ( xEnd != 0 || yEnd != 0 ) ) { var forward = new Snake( a0, N, b0, M, true, 0, VForward, k, d, pa, pb ); return new SnakePair { D = d, Reverse = reverse, Forward = forward }; } return new SnakePair { D = d, Reverse = reverse }; } } return null; }
//----------------------------------------------------------------------------------------- // MergeSnakes static IList<Snake> MergeSnakes( IList<Snake> snakes, int a0, int N, int b0, int M ) { var r = new List<Snake>( snakes.Count ); var c = new Snake( a0, N, b0, M, true, 0, 0, 0, 0, 0 ); foreach ( var s in snakes ) { if ( s.IsForward ) { if ( ( s.ADeleted > 0 || s.BInserted > 0 ) && c.DiagonalLength > 0 ) { r.Add( c ); c = new Snake( a0, N, b0, M, true, c.XEnd, c.YEnd, 0, 0, 0 ); } c.ADeleted += s.ADeleted; c.BInserted += s.BInserted; c.DiagonalLength += s.DiagonalLength; Debug.Assert( c.EndPoint == s.EndPoint ); } else { c.DiagonalLength += s.DiagonalLength; if ( ( s.ADeleted > 0 || s.BInserted > 0 ) && c.DiagonalLength > 0 ) { r.Add( c ); c = new Snake( a0, N, b0, M, true, c.XEnd, c.YEnd, 0, 0, 0 ); } c.ADeleted += s.ADeleted; c.BInserted += s.BInserted; Debug.Assert( c.EndPoint == s.StartPoint ); } } if ( c.StartPoint != c.EndPoint ) r.Add( c ); return r; }
static void Compare( int recursion, List<Snake> snakes, string[] pa, int a0, int N, string[] pb, int b0, int M, V VForward, V VReverse ) { //Debug.WriteLine( new String( '-', recursion ) + recursion + "> Compare( " + a0 + ", " + b0 + " ) + ( " + N + ", " + M + " ) = ( " + ( a0 + N ) + ", " + ( b0 + M ) + " )" ); if ( N == 0 && M > 0 ) { var down = new Snake( a0, N, b0, M, true, a0, b0, 0, M, 0 ); //Debug.WriteLine( "down: " + down ); snakes.Add( down ); } if ( M == 0 && N > 0 ) { var right = new Snake( a0, N, b0, M, true, a0, b0, N, 0, 0 ); //Debug.WriteLine( "right: " + right ); snakes.Add( right ); } if ( N <= 0 || M <= 0 ) return; SnakePair? middle = null; VForward[ 1 ] = 0; //VReverse[ N - M - 1 ] = N; middle = DiffCommon.CalcForD.MiddleSnake( pa, a0, N, pb, b0, M, VForward, VReverse ); if ( middle == null ) throw new ApplicationException( "No middle snake" ); var m = middle.Value; int d = middle.Value.D; //Debug.WriteLine( "d:" + d + " " + m.Forward + " " + m.Reverse ); if ( d > 1 ) { var xy = ( m.Forward != null ? m.Forward.StartPoint : m.Reverse.EndPoint ); var uv = ( m.Reverse != null ? m.Reverse.StartPoint : m.Forward.EndPoint ); Compare( recursion + 1, snakes, pa, a0, xy.X - a0, pb, b0, xy.Y - b0, VForward, VReverse ); if ( m.Forward != null ) snakes.Add( m.Forward ); if ( m.Reverse != null ) snakes.Add( m.Reverse ); Compare( recursion + 1, snakes, pa, uv.X, a0 + N - uv.X, pb, uv.Y, b0 + M - uv.Y, VForward, VReverse ); } else { if ( m.Forward != null && m.Reverse != null ) // check for overlapping diagonal if ( m.Forward.XMid - m.Forward.YMid == m.Reverse.XMid - m.Reverse.YMid ) { m.Forward.DiagonalLength = m.Reverse.XMid - m.Forward.XMid; m.Reverse.DiagonalLength = 0; } if ( m.Forward != null ) { // D0 if ( m.Forward.XStart > a0 ) { if ( m.Forward.XStart - a0 != m.Forward.YStart - b0 ) throw new ApplicationException( "Missed D0 forward" ); snakes.Add( new Snake( a0, N, b0, M, true, a0, b0, 0, 0, m.Forward.XStart - a0 ) ); } snakes.Add( m.Forward ); } if ( m.Reverse != null ) { snakes.Add( m.Reverse ); // D0 if ( m.Reverse.XStart < a0 + N ) { if ( a0 + N - m.Reverse.XStart != b0 + M - m.Reverse.YStart ) throw new ApplicationException( "Missed D0 reverse" ); snakes.Add( new Snake( a0, N, b0, M, true, m.Reverse.XStart, m.Reverse.YStart, 0, 0, a0 + N - m.Reverse.XStart ) ); } } } }
static SnakeWithCharResults ConvertToLines( CompareCharsData data, bool deleted, IList<Snake> chars, Snake lineSnake ) { //Debug.WriteLine( "\nConvertToLines " + ( deleted ? "DELETED" : "INSERTED" ) ); //Debug.WriteLine( data.ToString() ); var list = new List<CharSnake>(); foreach ( var s in chars ) { //Debug.WriteLine( "Char " + s ); int lStart, cStart, lMid, cMid, lEnd, cEnd; data.LineFromChar( deleted ? s.XStart : s.YStart, out lStart, out cStart ); data.LineFromChar( deleted ? s.XMid : s.YMid, out lMid, out cMid ); data.LineFromChar( deleted ? s.XEnd : s.YEnd, out lEnd, out cEnd ); //Debug.WriteLine( "LINE:CHAR Start: " + lStart + ":" + cStart + " Mid: " + lMid + ":" + cMid + " End:" + lEnd + ":" + cEnd ); if ( deleted ? s.ADeleted > 0 : s.BInserted > 0 ) { for ( int l = lStart ; l <= lMid ; l++ ) { var cs = new CharSnake(); cs.Line = l; cs.IsDeleted = deleted; cs.CharStart = ( l == lStart ? cStart : 0 ); var end = ( l == lMid ? cMid : data.LineLength( l ) ); cs.Diff = end - cs.CharStart; cs.IsEOL = data.IsEOL( l, end ); //Debug.WriteLine( "Diff " + cs + " = '" + data.Substring( cs.CharStart, cs.Diff ) + "'" ); if ( cs.Diff > 0 || data.LineLength( l ) == 0 ) list.Add( cs ); } } if ( s.DiagonalLength > 0 ) { for ( int l = lMid ; l <= lEnd ; l++ ) { var cs = new CharSnake(); cs.Line = l; cs.IsDeleted = deleted; cs.CharStart = ( l == lMid ? cMid : 0 ); var end = ( l == lEnd ? cEnd : data.LineLength( l ) ); cs.Same = end - cs.CharStart; cs.IsEOL = data.IsEOL( l, end ); //Debug.WriteLine( "Same " + cs + " = '" + data.Substring( cs.CharStart, cs.Same ) + "'" ); if ( cs.Same > 0 || data.LineLength( l ) == 0 ) list.Add( cs ); } } } return new SnakeWithCharResults( lineSnake, list ); }